I need to run a function every time I scroll to the bottom and increment a counter, but the counter should only go up to 4, everything after that should be ignored. My current attempt looks like this
const [ fCount, setFCount ] = useState(1);
useEffect(() => {
window.addEventListener('scroll', () => {
if ((window.innerHeight window.pageYOffset) >= document.body.offsetHeight && fCount < 5) {
setFCount(fc => fc 1);
console.log(fCount)
}
})
}, []);
However it doesn't work, it just logs the initial value (1) as many times as I scroll to the bottom. And if I add the fCount value to the dependency array, then it logs
1
1
2
1
2
3
1
2
3
4
Just so we're clear, the counter is extended by another part of the app, it's not just for the lolz. How can I get a normal counter that logs 1-2-3-4 when you scroll enough times to the bottom?
CodePudding user response:
Some of your code is referencing the fCount
closure variable. The value of that is locked in when the effect ran, so it will always be 1. When you set the state though, you're doing it right: setFCount(fc => fc 1);
. That function gets passed the latest value of the state.
The fix is to move all the code that needs the latest value into that function:
useEffect(() => {
window.addEventListener('scroll', () => {
setCount(fc => {
if ((window.innerHeight window.pageYOffset) >= document.body.offsetHeight && fc < 5) {
console.log(fc 1);
return fc 1;
} else {
return fc;
}
});
})
}, []);
P.S, don't forget to clean up your effect and tear down the event listener:
useEffect(() => {
const onScroll = () => {
setCount(fc => {
if ((window.innerHeight window.pageYOffset) >= document.body.offsetHeight && fc < 5) {
console.log(fc 1);
return fc 1;
} else {
return fc;
}
});
}
window.addEventListener('scroll', onScroll);
return () => {
window.removeEventListener('scroll', onScroll);
}
}