0

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.

2
  • Take a look at react-query, it might be able to help simplify your logic so you don't have to deal with this. Commented Nov 3, 2020 at 18:36
  • I've already tried this, I'm getting the same thing, nbrPages still equals to 0. Commented Nov 3, 2020 at 18:38

3 Answers 3

1

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]); 
Sign up to request clarification or add additional context in comments.

4 Comments

What is nbrItems here ? response.data.length%nbrItems > 0 ? setNbrPages((response.data.length/nbrItems)+1) : setNbrPages(response.data.length/nbrItems)
it's a state variable which is predefined, its the number of items I've to show by default.
It seems that the state doesn't get updated immediately, so the loop doesn't executes since nbrPages equals to 0.
So you can use another useEffect to update the setPages(). I am adding the update code .
0
  • 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.
  • Passing an empty array as a parameter works as componentDidMount which means it would get triggered only once at the start.

Comments

0

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

  1. Avoid using axios create instance for now till you can backtrace your error

  2. Avoid inner logic of saving contents in state for now just console.log your contents and see what is happening

  3. 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

2 Comments

nbrPages is still equals to 0.
Issue could definitely be in your function but not the useEffect... You know what a good debugging technique is try a make a request in the simplest way check code that I will add in answer then build up from the and see what is bugging because it could be your addon logic that is breaking

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.