stanleysearles
stanleysearles

Reputation: 45

clearInterval not working inside setInterval

I'm trying to build a countdown timer, which has a single button to toggle the start and the stop of the timer. Starting the timer and the switch between "break mode" and "session mode" works fine. The initial state of the countdown timer is paused. When I click on the Toggle Button it starts normally. When I click again, it doesn't do anything, it doesn't clear the interval. When I click again however, it doubles the interval.

Here is my code so far - the countdown function and the toggle function:

  startstop() {
    if (this.state.paused){
      this.setState({
        paused: false,
      });
      this.countdown(this.state.timerseconds, this.state.timerminutes, this.state.sessiontrue, this.state.paused);
    } else if (!this.state.paused){
      this.setState({
        paused: true,
      });
      this.countdown(this.state.timerseconds, this.state.timerminutes, this.state.sessiontrue, this.state.paused);
    }
  }

 countdown(seconds, minutes, sessionactive, pausedtrue){
  let s = seconds;
  let m = minutes;
  let interval = setInterval(() => {
    if (pausedtrue){
      clearInterval(interval);
    } else {
      if (s === 0 && m > 0){
        this.setState({
          timerseconds: 59,
          timerminutes: this.state.timerminutes - 1
        })
        s = 59;
        m = m - 1;
      } else if (s > 0 && m >= 0) {
        this.setState({
          timerseconds: this.state.timerseconds - 1,
          timerminutes: this.state.timerminutes
        })
        s = s - 1;
      } else if (s === 0 && m === 0){
        if (sessionactive){
          clearInterval(interval);
          document.getElementById("beep").play();
          this.setState({
            timerseconds: 0,
            timerminutes: this.state.breaklength,
            sessiontrue: false,
          });
          this.countdown(this.state.timerseconds, this.state.timerminutes, this.state.sessiontrue, false);
        } else {
          clearInterval(interval);
          document.getElementById("beep").play();
          this.setState({
            timerseconds: 0, 
            timerminutes: this.state.sessionlength,
            sessiontrue: true,
          });
          this.countdown(this.state.timerseconds, this.state.timerminutes, this.state.sessiontrue, false)
        }
      }
    }
  }
, 1000)
}

Upvotes: 0

Views: 122

Answers (1)

Egan Wolf
Egan Wolf

Reputation: 3573

Every time you call countdown you create a new interval. You should store the reference to the first interval somewhere and use that reference in clearInterval when you click to pause the timer.

Another approach would be to use this.state.paused instead of pausedtrue in if (pausedtrue), because pausedtrue is set when you call the method and never changes but this.state.paused can be changed and will be checked every tick.

Also I think it's not safe to use this.state.paused when you call the countdown. setState is asynchronous so you never know if the value in the state has been already changed or not.

Upvotes: 1

Related Questions