Using setInterval() to make a session timer with ReactJS hooks: error messages, irregular counting and “null” output

I’m trying to make a timer that will start (at 00:00) when the user loads the Home page, increment every second, and reset to 00:00 when they go to a different page.

Here’s my newest code:

  const [ timerCount, increaseTimer ] = useState(0);

  function timerItself() {
    function timerIncrement() {
      var currentTimerCount = timerCount;
      increaseTimer(currentTimerCount + 1);
    };
    setInterval(() => timerIncrement, 1000);
    clearInterval(timerIncrement);
    return;
  }

  function pageHome() {
    var timerMinutes = JSON.stringify(Math.floor(timerItself / 60));
    var timerSeconds = JSON.stringify(timerItself % 60);

    timerItself();

    return (
      <div classname="App">
        <header className="App-header">
          <h1>Hello world!</h1>
          <img src={logo} className="App-logo" alt="logo" />
          <p>{timerMinutes.padStart(2, '0')}:{timerSeconds.padStart(2, '0')}</p>
          <p>
            <button onClick={(() => changePage('About'))}>
              About
            </button>
            <button onClick={(() => changePage('Help'))}>
              Help
            </button>
          </p>
        </header>
      </div>
    );
  }

Previously I had wrapped the setInterval() in a const like so: const timer = setInterval(() => increaseTimer(timerCount + 1), 1000); and tried putting clearInterval() in the buttons’ onClick functions thinking this would just reset the timer.

The output had weird behaviour: the timer would count up at irregular intervals, starting very slow from 00:03 instead of 00:00 and becoming very fast. The sequence of times shown was consistent but I couldn’t recognise it as a mathematical sequence: 3, 7, 11, 29… 81… and reaching very high numbers within about 30 seconds. Couldn’t figure out where in the code the numbers were coming from.

I did some more reading and came to the conclusion that timer was setting off more than one timer at the same time and somehow adding their outputs together. So I wrote timerItself() instead, with a clearInterval() in there which I assumed would also fire every second to clear the old timer and clean up for the new one. But now there’s no counting going on at all, and the stringified output from the timer is “null:null”.

I’m confused over where the clearInterval() should even go, as I think that’s the main key to this problem. I’d really appreciate any help.

Answer

Solved!

This code is working well for my purposes:

  const [ timer, changeTimer ] = useState(0);
  var currentTimerCount = timer;

  useEffect(() => {
    if (page !== 'Home')
      changeTimer(0);
    if (page == 'Home')
      currentTimerCount = setInterval(() => {changeTimer(prevTimer => prevTimer + 1)}, 1000);
      return () => clearInterval(currentTimerCount);
  });

  var timerMinutes = JSON.stringify(Math.floor(currentTimerCount / 60));
  var timerSeconds = JSON.stringify(currentTimerCount % 60);

and then calling timerMinutes and timerSeconds as before.

Thanks to everyone who answered!