1

Hello mighty people from internet,

I am trying to build a countdown timer app with pause and reset buttons using React hooks.

The timer countdown should stop once pause or reset button gets clicked performed by function pauseCountDown() and reset(), respectively.

However, the timer does not stop after pauseCountDown() or reset() executed. I don’t quite understand why setInterval() does not stop after clearInterval() gets executed.

clearInterval() should be executed when isPaused === true. However, the value of “isPaused” instantly switches back to false along with the next iteration of nonstopped setInterval().

Any ideas or thoughts what I missed or mistakes I have?

Thank you.

Here is the code of the child component performing timer countdown:

function TimerPanel(props) {
  var launch;
  var secLeft = parseInt(props.timerNow.min) * 60 + parseInt(props.timerNow.sec)

  const startCountDown = () => {
    props.setIsPaused(false)
    launch = setInterval(decrement, 1000)
  }
  function decrement() {
    if (secLeft > 0 && !props.isPaused) {
      secLeft--;
      var minCountDown = Math.floor(secLeft / 60)
      var secCountDown = Math.floor((secLeft % 60) * 100) / 100
      props.setTimerNow({...props.timerNow, min: minCountDown, sec: secCountDown})
    }
  }
  const pauseCountDown = () => {
    props.setIsPaused(true)
    clearInterval(launch)
  }
  const reset = () => {
    props.setIsPaused(false)
    clearInterval(launch)
    props.setSessionLength(props.initialTimer.min);
    props.setTimerNow({...props.timerNow, min: props.initialTimer.min, sec: props.initialTimer.sec})
  }
0

1 Answer 1

3

Since launch is just an ordinary variable, its value will not survive across rerenderings of TimerPanel. You'll need to store it inside a ref with useRef

// add useRef to your imports from react
import { useRef } from "react";

function TimerPanel(props) {
  const launch = useRef();
  var secLeft =
    parseInt(props.timerNow.min) * 60 + parseInt(props.timerNow.sec);

  const startCountDown = () => {
    props.setIsPaused(false);
    clearInterval(launch.current) // clean up any old timers
    launch.current = setInterval(decrement, 1000);
  };
  function decrement() {
    if (secLeft > 0 && !props.isPaused) {
      secLeft--;
      var minCountDown = Math.floor(secLeft / 60);
      var secCountDown = Math.floor((secLeft % 60) * 100) / 100;
      props.setTimerNow({
        ...props.timerNow,
        min: minCountDown,
        sec: secCountDown,
      });
    }
  }
  const pauseCountDown = () => {
    props.setIsPaused(true);
    clearInterval(launch.current);
  };
  const reset = () => {
    props.setIsPaused(false);
    clearInterval(launch.current);
    props.setSessionLength(props.initialTimer.min);
    props.setTimerNow({
      ...props.timerNow,
      min: props.initialTimer.min,
      sec: props.initialTimer.sec,
    });
  };

  // ...
}
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you very much! It works! However, I am still not crystal clear what's reason behind this. "launch" is only used within this child component for setInterval(). It is not needed in its parent component. By the same logic, how about secLeft? It is used to store the length of time. Should we also ref for secLeft as well?
It looks like secLeft is calculated from props. I didn't notice that you modify it in decrement - you should probably just not modify it in decrement and just derive it from props.timerNow.min and props.timerNow.sec.
refs are like instance variables in a class, if you're familiar with object-oriented programming.
secLeft is the total time period in the format of seconds, derived from props.timerNow.min and props.timerNow.sec. Any reason why we should avoid using secLeft? I can remove secLeft and just use props.timerNow.min and props.timerNow.sec directly but just using secLeft makes the code a bit more tidy and readable.
Yes, that's fine, secLeft-- is just redundant then.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.