let updateTimer: number;
export function Timer() {
const [count, setCount] = React.useState<number>(0);
const [messages, setMessages] = React.useState<string[]>([]);
const start = () => {
updateTimer = setInterval(() => {
const m = [...messages];
m.push("called");
setMessages(m);
setCount(count + 1);
}, 1000);
};
const stop = () => {
clearInterval(updateTimer);
};
return (
<>
<div>{count}</div>
<button onClick={start}>Start</button>
<button onClick={stop}>Stop</button>
{messages.map((message, i) => (
<p key={i}>{message}</p>
))}
</>
);
}
Code Sample: https://codesandbox.io/s/romantic-wing-9yxw8?file=/src/App.tsx
The code has two buttons - Start and Stop.
Start calls a
setInterval
and saves interval id. Timer set to 1 second (1000 ms).Stop calls a
clearInterval
on the interval id.
The interval id is declared outside the component.
The interval callback function increments a counter and appends a called
message to the UI.
When I click on Start, I expect the counter to increment every second and a corresponding called
message appended underneath the buttons.
What actually happens is that on clicking Start, the counter is incremented just once, and so is the called
message.
If I click on Start again, the counter is incremented and subsequently reset back to its previous value.
If I keep clicking on Start, the counter keeps incrementing and resetting back to its previous value.
Can anyone explain this behavior?
useEffect
callback return function to also clear the interval when unmounting so there isn't a "can't update XXX of unmounted" error. – Autotruck