According to the React docs as well as every example on stackoverflow for timers, people use something similar to Option 2 w/ useEffect (+useState) to create a timer that you can start/pause/reset.
However, I've also been able to create a timer in Option 1 by solely using useState.
Why does nobody rely on useState for timers? I understand that useEffect cleans up during unmounting/re-rendering, but does this really improve performance? Wouldn't the constant unmounting and remounting from useEffect and then calling setValue be slower than just executing a regular function that calls setValue? Both options can call clearInterval, so shouldn't either be sufficient for clean-up?
Also, which timer would be more "accurate", Option 1 or 2? I believe I understand how the Event Loop for async functions works, but in React it becomes a bit foggy to me. Would there ever be a case where multiple async functions are backlogged and somehow delay useEffect from triggering and making the timer in Option 2 tick at a slower rate than Option 1 (i.e. not ticking exactly every second and slowly lagging behind the other timer)?.
Thank you!
Option 1 - regular function + useState
const [time, setTime] = useState(1500);
const [startPauseBtnText, setStartPauseBtnText] = useState('START');
const timeID = useRef(null);
const startPauseTime = () => {
if (timeID.current) {
clearInterval(timeID.current);
timeID.current = null;
setStartPauseBtnText('START');
} else {
timeID.current = setInterval(() => {
setTime((prevTime) => {
return prevTime - 1;
});
}, 1000);
setStartPauseBtnText('PAUSE');
}
};
const resetTime = () => {
clearInterval(timeID.current);
timeID.current = null;
setTime(1500);
};
Option 2 - useEffect + useState
const [isActive, setIsActive] = useState(false);
const [time2, setTime2] = useState(1500);
useEffect(() => {
let timeID2;
if (isActive) {
timeID2 = setInterval(() => {
setTime2((prevTime) => {
return prevTime - 1;
});
}, 1000);
}
return () => clearInterval(timeID2);
}, [isActive, time2]);
const resetTime2 = () => {
setIsActive(false);
setTime2(1500);
};