Is there a reason why my clearInterval function isnt working in React?

CHRIS EKE

I've created a simple timer script initialized with 10 seconds for testing. The problem I'm having is that the pause timer button isn't working as expected.

import React, { useState } from 'react';

function App() {

  const [time, updateTime] = useState(() => { return 10 });
  const [timerRunning, setTimerRunning] = useState(false);
  
  let minutes = Math.floor(time / 60);
  let seconds = time % 60;
  let interval;

  function startTimer() {
    setTimerRunning(true);
    interval = setInterval( function() {
      updateTime(previousTime => previousTime === 0 ? previousTime : previousTime - 1);
    }, 1000);
  }

  function pauseTimer() {
    setTimerRunning(false);
    clearInterval(interval);
  }

  function restartTimer() {
    setTimerRunning(false);
    updateTime(() => {return 10});
  }

  return (
    <>
      <p>{minutes > 9 ? minutes : "0" + minutes}:{seconds > 9 ? seconds : "0" + seconds}</p>
      <button onClick={startTimer}>Start</button>
      <button onClick={pauseTimer}>Pause</button>
      <button onClick={restartTimer}>Restart</button>
    </>
  )
}

export default App;

I want the pause button to pause the timer. Eventually I'll make conditional statements to have each button appear based on the state of the app and the value of time, but the pause button is my current obstacle.

I first had a separate countdown function which used a conditional to stop the time when the time matched counter (below). I thought of a less complicated way that lets me omit the counter variable (above). Im not sure which option is better, or if either is preventing the clearInterval function to work properly. The clearInterval function works within the countdown function if statement, but will not work outside of it.

import React, { useState } from 'react';

function App() {

  const [time, updateTime] = useState(() => { return 10 });
  const [timerRunning, setTimerRunning] = useState(false);
  
  let counter = 0;
  let minutes = Math.floor(time / 60);
  let seconds = time % 60;
  let interval;

  function countdown() {
    counter++;
    if ( counter === time ) {
       setTimerRunning(false);
       clearInterval(interval);
    }
      updateTime(previousTime => previousTime - 1);
  }
  

  function startTimer() {
    setTimerRunning(true);
    interval = setInterval(countdown, 1000);
  }

  function pauseTimer() {
    setTimerRunning(false);
    clearInterval(interval);
  }

  function restartTimer() {
    setTimerRunning(false);
    updateTime(() => {return 10});
  }



  return (
    <>
      <p>{minutes > 9 ? minutes : "0" + minutes}:{seconds > 9 ? seconds : "0" + seconds}</p>
      <button onClick={startTimer}>Start</button>
      <button onClick={pauseTimer}>Pause</button>
      <button onClick={restartTimer}>Restart</button>
    </>
  )
}

export default App;
Kalhan.Toress

Basically you can't create let interval; and assign it a setInterval like interval = setInterval(countdown, 1000);

because on each re-render there will be new let interval;

what you need to do is create a variable which isn't change on re-redners, you can use useRef

const interval = useRef(null);
.....
function startTimer() {
    interval.current = setInterval(countdown, 1000);
}
....
function pauseTimer() {
   clearInterval(interval.current);
}

and I don't think you need const [timerRunning, setTimerRunning] = useState(false);

find a demo here

Basically when functional component re-renders it will execute from top to bottom, if you use like let counter = 0;, then on each re-render it will initialize to 0, if you need to persists your values in each re-renders you might need some hooks (Ex: useState, useRef ...), in this case useRef would do the trick (because you need only one setInterval in each re-renders and useRef will give you the previous value, it will not re-initalize like a general variable)

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related