[SOLVED] React hooks – Can't use hook inside plain async function?

Issue

I’m new to hooks and have been mildly impressed thus far, however, it seems to complain if I try to use hooks inside a function (Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons).

I have several common API functions inside a base file which are used to retrieve data from the API. They do NOT return anything and merely dispatch (useDispatch) to the store and the associated components using this state are updated throughout the app. I understand that is probably the reason as it’s not returning a React element, but is there a way around this or a better, more “recommended” React approach? It’s not the end of the world if I have to manually pass in the user and dispatch on the returned result in the parent component, but I’d rather keep it in one place and handle it all in this function so all the parent component has to do is update when the state changes.

This is the function:

export async function getCar(id) {

  // It's complaining about these hooks
  const { user } = useSelector(state => state.auth);
  const dispatch = useDispatch();

  try {
      let response = await axios.get(`${baseURL}api/cars/getCar/${id}/${user.id});
      if (response.data.successCode === 200) dispatch(setCar(response.data));
  } catch (error) {

  }
}

USAGE: const carsList = getCar("id");

Thanks all,
Much appreciated.

Solution

Hook are different from function. Considering you want to implement a custom hook, you first need to prefix your hook name with use

Secondly hooks can’t return async values unless you store it in state. Also you need to make use of useEffect function to make sure that the api request is only fired once or on change of id param.

export function useGetCar(id) {
  // It's complaining about these hooks
  const { user } = useSelector(state => state.auth);
  const dispatch = useDispatch();
  useEffect(() => {
     async function myFn() {
        try {
              let response = await axios.get(`${baseURL}api/cars/getCar/${id}/${user.id});
              if (response.data.successCode === 200) dispatch(setCar(response.data));
        } catch (error) {

        }

      }
      fn()
  }, [id])
}

Also since you are just updating the state you could write another selector to get the car value from redux store

usage:

const Comp = ({id}) => {
    useGetCar(id);
    const car = useSelector(state => state.car);
}

Answered By – Shubham Khatri

Answer Checked By – Candace Johnson (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published.