skip to Main Content

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

Answers


  1. 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;
    
    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search