简体   繁体   中英

Infinite Loop with useEffect - ReactJS

I have a problem when using the useEffect hook, it is generating an infinite loop.

I have a list that is loaded as soon as the page is assembled and should also be updated when a new record is found in "developers" state.

See the code:

  const [developers, setDevelopers] = useState<DevelopersData[]>([]);

  const getDevelopers = async () => {
    await api.get('/developers').then(response => {
      setDevelopers(response.data);
    });
  };
  
  // This way, the loop does not happen
  useEffect(() => {
    getDevelopers();
  }, []);

  // This way, infinte loop
  useEffect(() => {
    getDevelopers();
  }, [developers]);

  console.log(developers)

If I remove the developer dependency on the second parameter of useEffect, the loop does not happen, however, the list is not updated when a new record is found. If I insert "developers" in the second parameter of useEffect, the list is updated automatically, however, it goes into an infinite loop.

What am I doing wrong?

complete code (with component): https://gist.github.com/fredarend/c571d2b2fd88c734997a757bac6ab766

Print: 在此处输入图片说明

The dependencies for useEffect use reference equality, not deep equality. (If you need deep equality comparison for some reason, take a look at use-deep-compare-effect .)

The API call always returns a new array object, so its reference/identity is not the same as it was earlier, triggering useEffect to fire the effect again, etc.

Given that nothing else ever calls setDevelopers , ie there's no way for developers to change unless it was from the API call triggered by the effect, there's really no actual need to have developers as a dependency to useEffect ; you can just have an empty array as deps: useEffect(() => ..., []) . The effect will only be called exactly once.

EDIT: Following the comment clarification,

I register a developer in the form on the left [...] I would like the list to be updated as soon as a new dev is registered.

This is one way to do things:

The idea here is that developers is only ever automatically loaded on component mount. When the user adds a new developer via the AddDeveloperForm , we opportunistically update the local developers state while we're posting the new developer to the backend. Whether or not posting fails, we reload the list from the backend to ensure we have the freshest real state.

const DevList: React.FC = () => {
  const [developers, setDevelopers] = useState<DevelopersData[]>([]);

  const getDevelopers = useCallback(async () => {
    await api.get("/developers").then((response) => {
      setDevelopers(response.data);
    });
  }, [setDevelopers]);

  useEffect(() => {
    getDevelopers();
  }, [getDevelopers]);

  const onAddDeveloper = useCallback(
    async (newDeveloper) => {
      const newDevelopers = developers.concat([newDeveloper]);
      setDevelopers(newDevelopers);
      try {
        await postNewDeveloperToAPI(newDeveloper); // TODO: Implement me
      } catch (e) {
        alert("Oops, failed posting developer information...");
      }
      getDevelopers();
    },
    [developers],
  );

  return (
    <>
      <AddDeveloperForm onAddDeveloper={onAddDeveloper} />
      <DeveloperList developers={developers} />
    </>
  );
};

The problem is that your getDevelopers function, calls your setDevelopers function, which updates your developers variable. When your developers variable is updated, it triggers the useEffect function

  useEffect(() => {
    getDevelopers();
  }, [developers]);

because developers is one of the dependencies passed to it and the process starts over.

Every time a variable within the array, which is passed as the second argument to useEffect, gets updated, the useEffect function gets triggered

Use an empty array [] in the second parameter of the useEffect. This causes the code inside to run only on mount of the parent component.

useEffect(() => {
    getDevelopers();
  }, []);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM