2

I'm creating a countdown timer and I need to call clearInterval from a different function as I want to start and pause the countdown with two different buttons

Here's a piece of my code

const startCountdown = () => {
    const countdown = setInterval(() => {
      setSecondsElapsed(secondsElapsed => secondsElapsed - 1);
    }, 1000);
  };

  const pauseCountdown = () => {
    clearInterval(countdown);
  };

The countdown starts when I press the initial button but it doesn't pause when I press the button calling pauseCountdown()

3 Answers3

1

Use a React ref to hold the timer reference. When setting the interval store the countdown reference as the ref's current value, and in the other function clear the interval using the ref's current value.

const countDownRef = React.useRef();

const startCountdown = () => {
  countDownRef.current = setInterval(() => {
    setSecondsElapsed(secondsElapsed => secondsElapsed - 1);
  }, 1000);
};

const pauseCountdown = () => {
  clearInterval(countDownRef.current);
};
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
1

try declaring countdown globally so it can be accessed from any function. I'd also recommend using var instead of const for things that will be frequently redefined, such as a pausable countdown loop.

try this:

var countdown;

const startCountdown = () => {
    countdown = setInterval(() => {
      setSecondsElapsed(secondsElapsed => secondsElapsed - 1);
    }, 1000);
  };

  const pauseCountdown = () => {
    clearInterval(countdown);
  };
KCGD
  • 675
  • 6
  • 10
  • Well, other than declaring a variable `const` not allowing reassignment, it's a recommended to use `let` over `var` for scoping reasons. https://stackoverflow.com/a/11444416/8690857 – Drew Reese Jul 01 '21 at 15:58
0

The countdown value is inside the scope of startCountdown function hence it can not be accessed from pauseCountdown function which is not inside that very scope.

There are many different ways to do this job properly. I would advise you to be more structural with the help of new abstractions.

I may perhaps use a Countdown class for this job.

class Countdown {
  #sid;
  #start;
  constructor(start){
    this.#start = start;
  }
  startCountdown(){
    this.#sid = setInterval( _ => ( !this.#start && clearInterval(this.#sid)
                                  , console.log(this.#start--)
                                  )
                           , 1000
                           );
  }
  pauseCountdown(){
    clearInterval(this.#sid);
  }
}

var cd = new Countdown(10);
cd.startCountdown();
setTimeout(_ => cd.pauseCountdown(), 5001)
setTimeout(_ => cd.startCountdown(), 10000)

The private class fields #sid and #start keep the clearInterval id and starting value respectively. The thing is they are not exposed to the outer world.

Redu
  • 25,060
  • 6
  • 56
  • 76