In the code snippet below, I add a random number to an array every 3 seconds using setInterval. This goes well, until I try to also call the function on the first render (see the commented line). This gives me this error: Maximum update depth exceeded.
const [listItems, setListItems] = useState([]);
useEffect(() => {
function extendTheList() {
const randNr = Math.floor(Math.random() * 10);
setListItems([...listItems, randNr]);
}
// extendTheList();
const int = setInterval(() => {
extendTheList();
}, 3000);
return () => clearInterval(int);
}, [listItems]);
Sandbox: https://codesandbox.io/s/vigilant-shamir-ltkh6m?file=/src/App.js
CodePudding user response:
Remove the dependency to avoid infinite loop
const [listItems, setListItems] = useState([]);
useEffect(() => {
function extendTheList() {
const randNr = Math.floor(Math.random() * 10);
setListItems(listItems => [...listItems, randNr]);
}
extendTheList();
const int = setInterval(() => {
extendTheList();
}, 3000);
return () => clearInterval(int);
}, []);
https://codesandbox.io/s/goofy-stallman-e1m4wo
CodePudding user response:
You have listItems
in the dependency array of useEffect which will retrigger the useEffect every time you change listItems.
If you want to use the old value of the state use the function version of setState
const [listItems, setListItems] = useState([]);
useEffect(() => {
function extendTheList() {
const randNr = Math.floor(Math.random() * 10);
setListItems((currentItems) => [...currentItems, randNr]);
}
// extendTheList();
const int = setInterval(() => {
extendTheList();
}, 3000);
return () => clearInterval(int);
}, [setListItems]);
CodePudding user response:
First, you can move the declaration of extendTheList()
outside of the useEffect
hook. This will ensure that extendTheList()
is only called once on the first render, instead of every time listItems is updated.
const [listItems, setListItems] = useState([]);
function extendTheList() {
const randNr = Math.floor(Math.random() * 10);
setListItems([...listItems, randNr]);
}
useEffect(() => {
extendTheList();
const int = setInterval(() => {
extendTheList();
}, 3000);
return () => clearInterval(int);
}, []);
This code will call extendTheList()
on the first render, and then set up an interval to call it every 3 seconds after that. Because the useEffect
hook depends on an empty array, it will only be called once. This should avoid the "Maximum update depth exceeded" error.