ReactJS useEffect dependency warning leads to infninite loop

Viewed 118

In my functional component i have state and whenever it changes i want to do some stuff. So i used useEffect, but it gives "dependency missing" error. After i put all the dependencies shown in the error i get infinite loop. Here is the code:

const [keywords, setKeywords] = useState<Keyword[]>();
const [currentPage, pagingConfig, setPagingConfig] = usePaging();

  useEffect(() => {
    const loadKeywords = async () => {
      const { current, pageSize } = pagingConfig;
      const keywords = await getKeywords(current as number, pageSize as number);
      setKeywords(keywords.data.data);
      setPagingConfig({
        ...pagingConfig,
        total: keywords.data.total,
      });
    };
    loadKeywords();
  }, [currentPage]); // Requires to add pagingConfig and setPagingConfig

If required dependencies are added i get infinite loop.

How can i avoid this error?

3 Answers

Here is the way I look at it.

  • First up, I have seen the 'dependency missing' sentence too in my react coding. If I am not wrong, that is a warning. Perhaps, you can clarify. In my experience, you can ignore it, as long it is not affecting your final output. You have to remember that built in tools follow rules and semantics but you need to decide when a warning can be ignored.

  • Second, once you add the missing dependencies (to get rid of the warning), you are essentially making a state change inside your useEffect. By definiting, the view is rendered again, and you are back inside useEffect. So, that is why you are getting an infinite loop.

The solution is,

  • ignore the warning for now.
  • if you really want the warning to not be there, redesign your component or use Hooks to make sure that each component/Hook only deals with one part of your project.

The infinite loop happens because

  1. setPagingConfig updates the state within the useEffect
  2. useEffect reruns because the pagingConfig changed so a rerender happens with updated dependencies
  3. setPagingConfig updates the state within the useEffect

There you go, you have an infinite loop

You should only update the pagingConfig if it actually has a different keywords.data.total

In cases like this, the way to go is to do state changes only, if the value is changed:

const [keywords, setKeywords] = useState<Keyword[]>();
const [currentPage, pagingConfig, setPagingConfig] = usePaging();

useEffect(() => {
  const loadKeywords = async () => {
    const { current, pageSize } = pagingConfig;
    const newKeywords = await getKeywords(current as number, pageSize as number);
    if (newKeywords.data.data !== keywords) {
      setKeywords(newKeywords.data.data);
      setPagingConfig({
        ...pagingConfig,
        total: keywords.data.total,
      });
    }
  };
  loadKeywords();
}, [currentPage, pagingConfig, setPagingConfig]);

This way in the second iteration state is not updated anymore, because the keywords did not change.

Related