Stack Overflow Asked by Countour-Integral on January 5, 2022
First I declare these two varaibles to get and set the values I get from the axios request
let tmpFolder = [];
const [folder_JSX,setFolder_JSX] = useState([])
then I send the request
const sendRequest = () => {
return axios.get(`sample_url`).then(response => {return response.data})
}
sendRequest().then(folder=> {
//loop through each item and append a JSX element into the array
for (let i=0;i <folder.length;i++) {
tmpFolder.push(<Folder tags={folder[i].tags} name={folder[i].name} description={folder[i].description} date={folder[i].date_created[0]} tagOne={folder[i].tags[0]} tagTwo={folder[i].tags[1]} tagThree={folder[i].tags[2]} tagRest={folder[i].tags.length - 3} />)
}
setFolder_JSX(prev => tmpFolder) // <----- This line is causing an infinite loop
}).catch(err => console.log(err))
The compiler throws Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
which is True (when I remove one prop from the Folder JSX element it does not throw this error but keeps making requests infinitely)
– I set the folder state to that array.
The folder_JSX (which gets rendered in the dom) does not change, but the requests keep getting sent.
I can’t figure out what is causing the infinite loop
Every time the state updates, your component function is run again. Because you are calling sendRequest
each time the function is called, and then updating the state based on it, you get an endless cycle of rerenders.
You shouldn't be performing side effects - such as API calls - inside the main body of your function anyway. (If you've previously used class components in React, you should think of your function component as the equivalent of render
, which just computes the JSX output from the component's current props and state, and should perform no side effects.) When using hooks, you have the useEffect hook for things like this. And in particular, its second argument is an array of variables, for which the effect will only run when one of those values has changed since the last render. This is how you can prevent the effect running on each render - which you must prevent here to stop the infinite updates.
As far as I can tell, this request doesn't depend on any internal state, so it should probably only run when the component first renders. In that case, pass the empty array as second argument.
In short, you should rewrite your code like this:
useEffect(() => sendRequest().then(folder => {
//loop through each item and append a JSX element into the array
for (let i=0;i <folder.length;i++) {
tmpFolder.push(<Folder tags={folder[i].tags} name={folder[i].name} description={folder[i].description} date={folder[i].date_created[0]} tagOne={folder[i].tags[0]} tagTwo={folder[i].tags[1]} tagThree={folder[i].tags[2]} tagRest={folder[i].tags.length - 3} />)
}
setFolder_JSX(prev => tmpFolder)
}).catch(err => console.log(err)), []);
Answered by Robin Zigmond on January 5, 2022
It appears as though you have the fetch logic out in the open in the functional component body, something like:
const MyComponent = () => {
let tmpFolder = [];
const [folder_JSX, setFolder_JSX] = useState([]);
const sendRequest = () => {
return axios.get(`sample_url`).then(response => {
return response.data;
});
};
sendRequest() // <-- invoked each render cycle
.then(folder => {
//loop through each item and append a JSX element into the array
for (let i = 0; i < folder.length; i++) {
tmpFolder.push(
<Folder
tags={folder[i].tags}
name={folder[i].name}
description={folder[i].description}
date={folder[i].date_created[0]}
tagOne={folder[i].tags[0]}
tagTwo={folder[i].tags[1]}
tagThree={folder[i].tags[2]}
tagRest={folder[i].tags.length - 3}
/>
);
}
setFolder_JSX(prev => tmpFolder); // <-- state update triggers rerender
})
.catch(err => console.log(err));
...
};
If this is the case then sendRequest
is invoked each render cycle and ultimately updates component state which triggers another render, thus the infinite cycle.
Perhaps you wanted to only fetch data when the component mounts, you can use an effect to do any side-effects:
const MyComponent = () => {
let tmpFolder = [];
const [folder_JSX, setFolder_JSX] = useState([]);
useEffect(() => {
const sendRequest = () => {
return axios.get(`sample_url`).then(response => {
return response.data;
});
};
sendRequest()
.then(folder => {
//loop through each item and append a JSX element into the array
for (let i = 0; i < folder.length; i++) {
tmpFolder.push(
<Folder
tags={folder[i].tags}
name={folder[i].name}
description={folder[i].description}
date={folder[i].date_created[0]}
tagOne={folder[i].tags[0]}
tagTwo={folder[i].tags[1]}
tagThree={folder[i].tags[2]}
tagRest={folder[i].tags.length - 3}
/>
);
}
setFolder_JSX(prev => tmpFolder);
})
.catch(err => console.log(err));
}, []); // <-- empty dependency to run once on component mount
...
};
Answered by Drew Reese on January 5, 2022
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP