Jose
Jose

Reputation: 5210

React timer hanging on :00 (state not updating)

I have a basic timer in React functioning properly counting down. The only problem is that it keeps hanging for an extra second (or two) when the timer's seconds reach '00' before switching to '59'. I think I'm still not comfortable with state because I've spent some serious time debugging and can't seem to figure out the problem.

Any help is much appreciated. Thank you.

Code: (the problem seems to be inside the if statement in the timer function)

const Clock = React.createClass({

  getInitialState: function() {
    return { currentCount: this.props.minutes, seconds: 10 };
  },

  startTimer: function() {
    var intervalId = setInterval(this.timer, 1000);
    this.setState({ intervalId: intervalId, minutes: this.state.currentCount - 1 });
  },

  pauseTimer: function() {
    clearInterval(this.state.intervalId);
    this.setState({ intervalId: this.props.minutes });
  },

  timer: function() {
    var minutes = this.state.minutes;
    var seconds = this.state.seconds;

    if (seconds === '00') {
      this.setState({ minutes: '0' + minutes - 1, seconds: 60 });
      this.setState({ currentCount: minutes + ':' + seconds });
      console.log('min: ' + minutes, 'sec: ' + seconds);
    } else {
      seconds--;
      seconds = seconds < 10 ? '0' + seconds : seconds;
      minutes = minutes < 10 ? '0' + minutes : minutes;

      this.setState({ currentCount: minutes + ':' + seconds, minutes: this.state.minutes, seconds: seconds });
    }
  },

  componentWillReceiveProps: function(nextProps) {
    this.setState({ currentCount: nextProps.minutes });
  },

  render: function() {
    return (
      <section>
        <button onClick={this.startTimer}>Start</button>
        <button onClick={this.pauseTimer}>Pause</button>
        <br></br>
        {this.state.currentCount}
      </section>
    );
  }

});

module.exports = Clock;

Upvotes: 0

Views: 65

Answers (1)

Niels Heisterkamp
Niels Heisterkamp

Reputation: 735

Try to keep your display logic (left padding zeros to minutes and seconds) in the render function and tick over the minutes with 59 seconds instead of 60, for example: https://jsfiddle.net/reactjs/69z2wepo/

const Clock = React.createClass({

  getInitialState: function() {
    return { minutes: this.props.minutes, seconds: this.props.seconds };
  },

  startTimer: function() {
    var intervalId = setInterval(this.timer, 1000);
    this.setState({ intervalId: intervalId });
  },

  pauseTimer: function() {
    clearInterval(this.state.intervalId);
    this.setState({ intervalId: this.props.minutes });
  },

  timer: function() {
    var minutes = this.state.minutes;
    var seconds = this.state.seconds;

    if (seconds === 0) {
      this.setState({ minutes: minutes - 1, seconds: 59 });
    } else {
      seconds--;
      this.setState({ minutes: minutes, seconds: seconds });
    }
  },

  render: function() {
    var s = this.state.seconds,
        m = this.state.minutes;
    return (
      <section>
        <button onClick={this.startTimer}>Start</button>
        <button onClick={this.pauseTimer}>Pause</button>
        <br></br>
        {m < 10 ? '0' + m : m}:{s < 10 ? '0' + s : s}
      </section>
    );
  }

});

Upvotes: 1

Related Questions