clearInterval() doesn't stop setInterval() method

54 Views Asked by At

I would like to stop setInterval using clearInterval(). But intervalId is undefined. I don't know why.

import { useState } from 'react';

function Component() {
  const [counter, setCounter] = useState(0);

  function addToCounter() {
    setCounter((c) => c + 1);
  }

  let intervalId;

  function runInterval() {
    intervalId = setInterval(addToCounter, 1000);
    console.log(intervalId);
  }

  function stopInterval() {
    clearInterval(intervalId);
    console.log(intervalId);
  }

  return (
    <>
      <p>Value :{counter}</p>
      <button onClick={runInterval}>start interval</button>
      <button onClick={stopInterval}>stop interval</button>
    </>
  );
}
export default Component;

It works when line

intervalId = setInterval(addToCounter, 1000);

is replaced by

intervalId = setInterval(()=>console.log(intervalId), 1000);
2

There are 2 best solutions below

0
David On

addToCounter updates state, which re-renders the component, which declares a new intervalId so the one for your interval has been lost.

There are various ways to approach the overall goal, including the use of useEffect. For the least amount of changes to the current code, simply storing the interval identifier in state should at least persist it across renders. For example:

function Component() {
  const [counter, setCounter] = useState(0);
  const [intervalId, setIntervalId] = useState();

  function addToCounter() {
    setCounter((c) => c + 1);
  }

  function runInterval() {
    setIntervalId(setInterval(addToCounter, 1000));
  }

  function stopInterval() {
    clearInterval(intervalId);
  }

  return (
    <>
      <p>Value :{counter}</p>
      <button onClick={runInterval}>start interval</button>
      <button onClick={stopInterval}>stop interval</button>
    </>
  );
}
export default Component;
0
Mr. Terminix On

The answer is in how React works. In first case you pass function addToCounter to the interval. Function addToCounter have setCounter which is setter from useState hook. When there is a setting of a new state, React rerenders the component. On every rerender intervalId have undefined value at the beginning. For that it do not stops the interval, because the id is lost.

In the second case () => console.log() do not trigger rerender, the id is kept in intervalId and it works.