Search code examples
reactjsreact-reduxuse-effectinfinite-loop

React make an async call on data after retrieving it from the state


I need to make an async call after I get some data from a custom hook. My problem is that when I do it causes an infinite loop.

export function useFarmInfo(): {
  [chainId in ChainId]: StakingBasic[];
} {
  return {
    [ChainId.MATIC]: Object.values(useDefaultFarmList()[ChainId.MATIC]),
    [ChainId.MUMBAI]: [],
  };
}

// hook to grab state from the state
const lpFarms = useFarmInfo();
const dualFarms = useDualFarmInfo();

//Memoize the pairs
const pairLists = useMemo(() => {
  const stakingPairLists = lpFarms[chainIdOrDefault].map((item) => item.pair);
  const dualPairLists = dualFarms[chainIdOrDefault].map((item) => item.pair);
  return stakingPairLists.concat(dualPairLists);
}, [chainIdOrDefault, lpFarms, dualFarms]);

//Grab the bulk data results from the web
useEffect(() => {
  getBulkPairData(pairLists).then((data) => setBulkPairs(data));
}, [pairLists]);

I think whats happening is that when I set the state it re-renders which causes hook to grab the farms from the state to be reset, and it creates an infinite loop.

I tried to move the getBulkPairData into the memoized function, but that's not meant to handle promises.

How do I properly make an async call after retrieving data from my hooks?


Solution

  • I am not sure if I can give you a solution to your problem, but I can give you some hints on how to find out the cause:

    First you can find out if the useEffect hook gets triggered too often because its dependency changes too often, or if the components that contains your code gets re-mounted over and over again:

    Remove the dependency of your useEffect hook and see if it still gets triggered too often. If so, your problem lies outside of your component.

    If not, find out if the dependencies of your useMemo hook change unexpectedly:

    useEffect(()=>console.log("chainIdOrDefault changed"), [chainIdOrDefault]);
    useEffect(()=>console.log("lpFarms changed"), [lpFarms]);
    useEffect(()=>console.log("dualFarms changed"), [dualFarms]);
    

    I assume, this is the most likely reason - maybe useFarmInfo or useDualFarmInfo create new objects on each render (even if these objects contain the same data on each render, they might not be identical). If so, either change these hooks and add some memoization (if you have access to your code) or narrow down the dependencies of your pairLists:

    const pairLists = useMemo(() => {
      const stakingPairLists = lpFarms[chainIdOrDefault].map((item) => item.pair);
      const dualPairLists = dualFarms[chainIdOrDefault].map((item) => item.pair);
      return stakingPairLists.concat(dualPairLists);
    }, [lpFarms[chainIdOrDefault], dualFarms[chainIdOrDefault]]);