Home > Net >  useEffect calls itself too many times
useEffect calls itself too many times

Time:07-29

There is a tree-like structure which should be expanded to make all checked children visible.

Here is the code:

  const { data } = useGetData(); // react-query hook that gets data from an endpoint

Next, there is a function that returns an array with a node's parents nodes:

  const getAllParents = (key: string, parentNodes: string[]) => {
    Object.keys(data).forEach((itemKey: string) => {
      if (
        data[itemKey]?.hasChildren &&
        data[itemKey].children?.filter((child: string) => child === key).length
      ) {
        parentNodes.push(itemKey);
        getAllParents(itemKey, parentNodes);
      }
    });

    return parentNodes;
  };

And here is the useEffect, that should run once after the tree is loaded:

  useEffect(() => {
    let allParents: string[] = [];
    let uniqueParents: string[] = [];
    selectedItems.forEach((item) => {
      const itemParents: string[] = getAllParents(item, []);
      allParents = [...allParents, ...itemParents];
      uniqueParents = [...new Set(allParents)];
    });
    setExpandedItems(uniqueParents);
  }, [getAllParents, selectedItems, uniqueParents]);

The problem is that this useEffect run continuously. There is a way to stop it from doing that, by removing getAllParents from dependency array.

But doing this shows the warning: React Hook useEffect has a missing dependency: 'getAllParents'. Either include it or remove the dependency array.

Anyway, it still doesn't work fine, it should only run once when the tree is loaded. Any ideas how to do that?

UPDATE AFTER ADDING USECALLBACK:

I have wrapped getAllParents inside a useCallback:

const getAllParents = useCallback((key: string, parentNodes: string[]) => { ... }, [data]);

For useEffect:

  • if the dependency array is empty ([]): it doesn't run at all, the tree is not expanded

  • [getAllParents, selectedItems]: it will run forever again

  • [ selectedItems]: it seems to work fine but with the same warning about a missing dependency.

CodePudding user response:

If the getAllParents is defined inside the React component, useEffect will treat it as a new function with each render (comparing by reference). Try wrapping it with useCallback to avoid creating a new function for every render

CodePudding user response:

you can try to wrap the getAllParents function with React.useCallback hook

  • Related