简体   繁体   中英

How to prevent infinite loop in my React code when using setState inside useEffect

Please check the codesandbox: https://codesandbox.io/s/bold-hamilton-k1nzs

Moment I run the code I am getting an infinite loop, you can check the console to see how the entries increase exponentially. And eventually the website crashes.

I have a state variable like this:

const [checkbox, setCheckBox] = useState({});

Then I am calling a function inside useEffect:

useEffect(() => {
    createCheckbox();
  });

This is the createCheckbox function:

const createCheckbox = () => {
    let checkboxObj = {};
    rows.forEach((e) => {
      checkboxObj[e.id] = false;
    });
    setCheckBox(checkboxObj);
  };

I have a console.log at line 76 to showcase the problem. It is console.log(checkbox)

Any idea what is going on?

Use a dependency array for useEffect . So this:

  useEffect(() => {
    createCheckbox();
  });

Should be:

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

useEffect() , as you already know, accepts a dependency array as the second parameter. It will only run when any of the variables in the array change. When you run useEffect without the second parameter, it acts as componentDidMount and componentDidUpdate. So since you set a state in your dependency-less useEffect, the state change triggers it again and again thus creating an infinite loop of renders.

When calling useEffect with an empty dependency array, it will only run once on first render. And that's what you needed.

Issue

useEffect(() => {
  createCheckbox();
});

The useEffect hook has no dependency so it runs every time the component renders, and since the hook callback ultimately updates state, it triggers another render cycle. Rinse and repeat, ad nauseam (ie render looping).

Solution

Basically I want to initialize the checkbox as empty/false on first load.

You can use an useEffect with empty dependency array to run the effect once when the component mounts.

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

Or use lazy state initialization function with the useState hook.

const [checkbox, setCheckBox] = useState(() => {
  let checkboxObj = {};
  rows.forEach((e) => {
    checkboxObj[e.id] = false;
  });
  return checkboxObj;
});

Demo

编辑 how-to-prevent-infinite-loop-in-my-react-code-when-using-setstate-inside-useeffe

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