Problems with JS timer

Hey guys :slight_smile:

I’m working on the Pomodoro clock challenge slowly and having some problems with my
functions controlling the starting/stopping of the timer. When I click the start button I call the pauseTimer function, which then calls the timer() function as required. However somewhere along the way it broke and I can’t seem to fix it, any advice/help would be greatly appreciated :). Please see code below (Only copied what I believe are the relevant parts, see the link for full code):

class Timer extends React.Component {
  constructor(props) {
    super(props);
    this.state={
      sessionLen: 25,
      breakLen: 5,
      timer: "25:00",
      timeRemaining: 25 * 60,
      timerStarted: false,
      timerPaused: false
    }
    this.incBreak = this.incBreak.bind(this);
    this.decBreak = this.decBreak.bind(this);
    this.incSession = this.incSession.bind(this);
    this.decSession = this.decSession.bind(this);
    this.timer = this.timer.bind(this);
    this.pauseTimer = this.pauseTimer.bind(this);
    this.setTimeInSecs = this.setTimeInSecs.bind(this);
    this.restartTimer = this.restartTimer.bind(this);
  }

pauseTimer() {
    if((this.state.timerStarted === true) && (this.state.timerPaused === true)) {
      this.setState({
        timerPaused: false
      });
      this.timer();
    } else if((this.state.timerStarted === true) && (this.state.timerPaused === false)) {
      this.setState({
        timerPaused: true
      });
    } else if (this.state.timerStarted === false) {
      this.setState({
        timerStarted: true
      });
      this.timer();
    }
  }

timer() {
    let minutes = Math.floor(this.state.timeRemaining / 60);
    let seconds = this.state.timeRemaining % 60;
    seconds < 10 ? seconds = "0" + seconds : seconds;
    minutes < 10 ? minutes = "0" + minutes : minutes;
    if((this.state.timeRemaining > 0) && (this.state.timerPaused == false) && (this.state.timerStarted)) {
      this.setState({
        timeRemaining: this.state.timeRemaining - 1,
        timer: minutes + ":" + seconds
      });
      setTimeout(this.timer, 1000);
    } else if (this.state.timerPaused) {
      return;
    } 
  }

------------------------

<div id="timer-box">
          <h2 id="timer-label">Session Timer</h2>
          <h4 id="time-left">{time}</h4>
          <p id="starter"><a href="#" id="start_stop" onClick={this.pauseTimer}><i class="fas fa-play-circle"></i></a></p>
          <p id="restart"><a href="#" id="reset" onClick={this.restartTimer}><i class="fas fa-sync-alt"></i></a></p>
        </div>

Link to full code: https://codepen.io/english-teapot/pen/Lajoqx

I used console.log to check what was going on and I found out your function timer is only called once, when I click the start button. The reason? this.state.timerStarted evaluates to false so setTimeout is never called. I think this is due to setState being asynchronous. When you call timer synchronously, the state hasn’t been changed yet.

How to solve it? Check what React has to say about setState. Here’s an extract:

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback ( setState(updater, callback) ), either of which are guaranteed to fire after the update has been applied.

Btw if you want to display your boolean variables, call toString() on them like this:
<li>{this.state.timerStarted.toString()}</li>

1 Like

That makes sense - I seem to recall the lessons mentioning something about this. I’ll have to go over my notes and try refactoring a few things. Thanks a lot, this is just the nudge-in-the-right-direction I needed :slight_smile: