Reputation: 1428
I'm trying to build a simple count down timer using react hooks to count down 3 seconds. But after 3 seconds UI stop rendering but in console.log I can still is prints out every second. Why is the second array parameter in useEffect doesn't prevent this from happening?
function CounterGame() {
const [timeout, setTimeout] = React.useState(3);
React.useEffect(() => {
let id = window.setInterval(() => {
if (timeout > 0) {
setTimeout(x => x - 1 );
}
// this line keep executing even it timeout reach 0
console.log("in setInterval", timeout);
}, 1000)
return () => {
window.clearInterval(id);
}
}, [timeout])
return (
<div className="App">
See instructions.
<h1>{timeout} seconds</h1>
{!timeout && <button>Click</button>}
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<CounterGame />, rootElement);
Upvotes: 2
Views: 1900
Reputation: 2422
According to the React docs:
This is why React also cleans up effects from the previous render before running the effects next time.
Based on this, I believe that the cleanup function is not run until the next iteration of the useEffect
. In your example, after timeout
hits 0, the useEffect
will run 1 more time, setting up a new interval, but because timeout
is 0, it will not update the state, so the useEffect
won't be called on the next render. That means the cleanup function never gets called for that last iteration.
Upvotes: 3
Reputation: 149
This may works for you:
clearIntervel when timeOut is zero by adding condition in useEffect
React.useEffect(() => {
let id = window.setInterval(() => {
if (timeout > 0) {
setTimeout(x => x - 1 );
}
//clearIntervel here
if(timeout == 0){
window.clearInterval(id);
}
// this line keep executing even it timeout reach 0
console.log("in setInterval", timeout);
}, 1000)
return () => {
window.clearInterval(id);
}
}, [timeout])
Upvotes: 5