In a simple timer component, I want to start and stop it with buttons, but the interval does not stop with a simple clearInterval function. Is there something I am missing?
import React, { useState } from 'react'
export default function Timer3() {
const [seconds, setseconds] = useState(0)
let intervalId;
const startTimer = () => {
intervalId = setInterval(() => {
setseconds((pre) => pre + 1)
}, 1000)
}
const stopTimer = () => {
clearInterval(intervalId)
}
return (
<>
{seconds}
<button onClick={startTimer}>start</button>
<button onClick={stopTimer}>stop</button>
</>
)
}
I know that in the code above, there is a bug: if I press "Start" twice, it will count twice. I am going to fix this after finding out how to make it stop. There is also a solution on the web to use useEffect to run the timer, but I am not looking for code—just a simple answer as to why it does not work.
3
Answers
The issue is that each time the state updates it re-renders the component and the
intervalId
variable is redeclared and any previous value is lost, so when the stop button is clicked it doesn’t have a reference to the running timer’s id.You can fix this by using a React ref to store the interval id value. React refs persist render cycle to render cycle.
You can store intervalId in a ref useRef instead of re declaring it each time:
intervalId resets each time the component re-renders as its regular variable.
You can use useRef instead of useState and useEffect, useRef keeps the value and do not re-render when changes.
const intervalId = useRef(null);
In
startTimer
, assign the interval tointervalId.current
instead of justintervalId
.In
stopTimer
, callclearInterval(intervalId.current)
.