I'm trying to use a setInterval
and a clearInterval
within useEffect
React hook. The timer starts as expected, but it won't stop.
I am assigning setInterval
to intervalID
then calling clearInterval(intervalID)
useEffect(() => {
console.log(`isRunning changed to: ${state.isRunning}`); //isRunning changed to: start
let intervalID;
console.log(`initial interval is: ${intervalID}`); // initial interval is: undefined
if (state.isRunning === "start") {
intervalID = setInterval(() => {
console.log(`interval is: ${intervalID}`); // interval is: 7
console.log(`tic toc`);
dispatch({ type: "tic-toc" });
}, 1000);
} else if (state.isRunning === "stop") {
console.log("clearInterval stop!"); // when I set isRunning to stop, this log shows in the console, but the next line doesn't stop the timer.
clearInterval(intervalID);
}
}, [state.isRunning]);
full code: https://github.com/LazaroFilm/pomodoro
A function or block of code that is bound to an interval executes until it is stopped. To stop an interval, you can use the clearInterval() method. ... useEffect(() => { const interval = setInterval(() => { setSeconds(seconds => seconds + 1); }, 1000); return () => clearInterval(interval); }, []); ...
I did make a fiddle to test it, and it turns out clearInterval stops all future execution, even those that have already be queued.
Answer: Use the clearInterval() Method The setInterval() method returns an interval ID which uniquely identifies the interval. You can pass this interval ID to the global clearInterval() method to cancel or stop setInterval() call.
Calling clearInterval() inside setInterval() has no effect But after calling clearInterval(), it will continue to execute.
Therefore, you can simply clear the setInterval () timer in this clean-up function, for example in the following way: // ... useEffect( () => { const timerId = setInterval( () => { // do something }, 2000); return () => clearInterval(timerId); }, []); // ...
I watch the condition execute clearInterval (rungame) This should freeze the game before the snake can move outside the canvas. But it doesn’t? Even though I watch the condition execute the clear interval? The clearInterval is working. When an out of bounds condition occurs, the game function doesn’t get called again.
Because this useEffect will trigger whenever there is change in either count or timer. In your case you are changing timer in useEffect itself which is causing infinite rendering. So, remove timer from dependency array (or remove setTimer function in case you don't need it) and try!
You are adding setTimer in return and at the same time you are adding timer variable in dependency array which will cause infinite rendering. Because this useEffect will trigger whenever there is change in either count or timer.
I think you neither need to use useState
nor useRef
hooks for the intervalID
. Declare it outside the useEffect
but clear the interval in the cleanup function of the useEffect
hook like so
let intervalID;
useEffect(() => {
if (isRunning) {
intervalID = setInterval(() => {
dispatch({ type: "tic-toc" });
}, 1000);
}
return () => clearInterval(intervalID);
}, [isRunning]);
Whenever isRunning
changes the component will unmount, and the cleanup function will be executed. So, if the isRunning
has changed to false
then the timer should stop at the unmount, and when it's mounted again the condition in the if statement won't be met to run the setInterval, and thus the timer remains stopped. In my code I assumed isRunning
is boolean (which is the way I prefer it to be), and assumed it's "destructured" from the state
which I assume comes from useReducer
hook.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With