Reputation: 15
I use the useEffect hook to fetch data from database by calling another function getData, when I recieve the data I update the state.
const [employees, setEmployees] = useState([])
const [shownEmployees, setShownEmployees] = useState([])
const [nbrPages, setNbrPages] = useState(0)
const getData = () => {
axios.request(options).then((response) => {
setEmployees(response.data)
setShownEmployees(response.data.slice(0, nbrItems))
response.data.length%nbrItems > 0 ? setNbrPages((response.data.length/nbrItems)+1) : setNbrPages(response.data.length/nbrItems)
console.log(nbrPages)
}).catch((error) => console.log(error))
for(let i=0;i<nbrPages;i++){
pages_temp.push(i)
}
console.log(pages_temp.length)
setPages(pages_temp)
}
useEffect(() => {
getData()
},[])
The problem nbrPages
which is all the time 0, but when I put employees
to useEffect as dependency, useEffect is executing many times but this time the nbrPages
is bieng calculated. Can anyone explain this behaviour, I've tried every thing. Essentially I want to understand why useEffect
is getting executed infinitely when I give it employees
as dependency, at what moment employees
changes so it triggers the useEffect hook.
Upvotes: 0
Views: 84
Reputation: 5054
This is happening because you are updating the employees
in the state from the getData method.
setEmployees(response.data)
That is updating the employees
and every time the employees are updated the useEffect is being called.
Update: It seems your problem is not with useEffect. You can debug your code and see what is happening at this point,
response.data.length%nbrItems > 0 ? setNbrPages((response.data.length/nbrItems)+1) : setNbrPages(response.data.length/nbrItems)
You can rewrite this part as,
console.log(response.data.length);
console.log(nbrItems);
console.log(response.data.length % nbrItems);
if(response.data.length % nbrItems) {
let temp = (response.data.length/nbrItems)+1;
console.log('Temp:', temp);
setNbrPages(temp);
} else {
console.log('Inside else block');
let temp = response.data.length/nbrItems;
console.log('Inside else temp:', temp);
setNbrPages(temp);
}
And see what are the console logs and figure out if your value is alright.
Update2: You can use another useEffect to solve your problem.
const [employees, setEmployees] = useState([])
const [shownEmployees, setShownEmployees] = useState([])
const [nbrPages, setNbrPages] = useState(0)
const getData = () => {
axios.request(options).then((response) => {
setEmployees(response.data)
setShownEmployees(response.data.slice(0, nbrItems))
response.data.length%nbrItems > 0 ? setNbrPages((response.data.length/nbrItems)+1) : setNbrPages(response.data.length/nbrItems)
console.log(nbrPages)
}).catch((error) => console.log(error))
}
useEffect(() => {
getData()
},[])
useEffect(() => {
for(let i=0;i<nbrPages;i++){
pages_temp.push(i)
}
console.log(pages_temp.length)
setPages(pages_temp)
},[nbrPages]);
Upvotes: 1
Reputation: 1051
Key to rendering your useEffect once is applying a cleanup function
SOLUTION:
const [employees, setEmployees] = useState([])
const [shownEmployees, setShownEmployees] = useState([])
const [nbrPages, setNbrPages] = useState(0)
const [mounted, setMounted] = useState(true); //Add this state helping with clean see below in useEffect
const getData = () => {
axios.request(options).then((response) => {
setEmployees(response.data)
setShownEmployees(response.data.slice(0, nbrItems))
response.data.length%nbrItems > 0 ? setNbrPages((response.data.length/nbrItems)+1) : setNbrPages(response.data.length/nbrItems)
console.log(nbrPages)
}).catch((error) => console.log(error))
for(let i=0;i<nbrPages;i++){
pages_temp.push(i)
}
console.log(pages_temp.length)
setPages(pages_temp)
}
useEffect(() => {
if (mounted){
getData()
}
return ()=>{
setMounted(false); // Cleanup function so that function called inside renders once
}
},[mounted])//useEffect dependency is the state added that is **mounted**
Debugging your function making api call technique
Avoid using axios create instance for now till you can backtrace your error
Avoid inner logic of saving contents in state for now just console.log your contents and see what is happening
Once you have established 1 and 2 the you know you are on the right track and now you know that error was on your logic then fix from there
const getData = async() => {
const {data} = await axios.get(url)
console.log(data)
//Then if this console.log bring you back data that you want
//now start rebuilding your logic piece by piece so that if
//something bugs out you know that the previous step for sure is
//not the one cause you have validated it
}
So if you can take this debugging procedure then you will be on the right track
Upvotes: 0
Reputation: 1317
useEffect
when provided a prop/state as a parameter works exactly as componentDidUpdate
meaning it would render each time a change happens to this prop/state, in your case you pass employees
as a dependency which means it would get executed first and after each axios call the value gets updated that means it would trigger useEffect again and again and so on.componentDidMount
which means it would get triggered only once at the start.Upvotes: 0