I'm trying to build a countdown timer but I'm facing an issue which I don't understand. When I press start the timer works fine and the same goes when I pause it.
The problem is when i press the reset button, which is supposed to stop the countdown and reset it to its original value(at the moment 25).
When I press it the countdown stops, it goes to 25 but then it goes to the previous number. For instance if I press it at 16, it stops, goes to 25 and then back at 16 or 15.
I guess it has something to do with useEffect
since handleReset
updates both counter
and runnning
but I'm not really sure why.
If anyone could explain to me the reason that would be great.
Here's App.js
const App = () => {
const [counter, setCounter] = useState(25);
const [running, setRunning] = useState(false);
const handlePlayPause = () => {
running ? setRunning(false) : setRunning(true);
};
const handleReset = () => {
setRunning(false);
setCounter(25);
};
useEffect(() => {
if (running) {
counter > 0 && setTimeout(() => setCounter(counter - 1), 1000);
}
}, [counter, running]);
return (
<div className="container">
<h1>Pomodoro Timer</h1>
<div className="set-timer">
<Break />
<Session />
</div>
<Display counter={counter} />
<Controller handlePlayPause={handlePlayPause} handleReset={handleReset} />
</div>
);
};
And the full code here: https://codepen.io/mugg84/pen/yLepaKm?editors=0010
Thanks for your help!
Few things here I'd probably change.
First off, handleReset
shouldn't probably set running
to false
as the counter is still running. You only reset the value.
Then, to fix the issues I'd suggest using setInterval
and you need to use clearInterval
in combination with useRef
. The logic can be simplified, but this is more readable I guess.
const handleReset = () => {
// stop on reset
clearInterval(timer.current)
timer.current = undefined;
setCounter(25);
};
const timer = React.useRef(undefined);
React.useEffect(() => {
if (running) {
if (!timer.current) {
timer.current = setInterval(() => setCounter(prevCounter => prevCounter - 1), 1000);
} else if(counter == 0 && timer.current) {
// stop if reached 0
clearInterval(timer.current)
timer.current = undefined;
}
} else {
// stop if turned off
clearInterval(timer.current)
timer.current = undefined;
}
}, [counter, running]);