How to deal with nested useEffect?

Viewed 4329

Recently started using Hooks and, as cook as they are, they are giving me a bit of a headache.

I have a custom useFetch() hook that deals with fetching data from the API.

I also have a component where I need to use useFetch a few times and the results must be passed from one to another.

E.g.:

const ComponentName = () => {
  const { responseUserInfo } = useFetch('/userinfo')
  const { responseOrders } = useFetch(`/orders?id=${responseUserInfo.id}`)
  const { isOrderRefundable } = useFetch(`/refundable?id={responseOrders.latest.id}`)

  return <div>{isOrderRefundable}</div>

}

So, how do I actually "cascade" the hooks without creating 3 intermediate wrappers? Do I have to use HoC?

1 Answers

Your hook could return a callback, that when called does the API call:

  const [getUserInfo, { userInfo }] = useFetch('/userinfo');
  const [getOrders, { orders }] = useFetch(`/orders`)
  const [getOrderRefundable, { isOrderRefundable }] = useFetch(`/refundable`);

  useEffect(getUserInfo, []);
  useEffect(() => { if(userInfo) getOrders({ id: userInfo.id }); }, [userInfo]);
  useEffect(() => { if(orders) getOrderRefundable({ id: /*..*/ }); }, [orders]);

But if you always depend on the whole data being fetched, I'd just use one effect to load them all:

  function useAsync(fn, deps) {
    const [state, setState] = useState({ loading: true });
    useEffect(() => { 
       setState({ loading: true });
       fn().then(result => { setState({ result }); });
    }, deps);
    return state;
 }

 // in the component
 const { loading, result: { userInfo, orders, isRefundable } } = useAsync(async function() {
   const userInfo = await fetch(/*...*/);
   const orders = await fetch(/*...*/);
   const isRefundable = await fetch(/*...*/);
   return { userInfo, orders, isRefundable };
 }, []);
Related