Front End Project: Timer doesn't stop

Tell us what’s happening:
On my local project; everything seems right as rain. However when I put it on Codepen; the timer interval function keeps going. I don’t understand at all.
Your code so far
The pen in question: https://codepen.io/a2937/pen/BaWzQvd

And the code stored in the local file

import React from "react";
import './App.css';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      sessionSeconds: 1500,
      activeTimer: false,
      displayWorkMinutes: 25,
      displayBreakMinutes: 5,
      breakComponentEnabled: true,
      breakStarted: false,
      runOnce: false
    }
    this.toggleTimer = this.toggleTimer.bind(this);
    this.incrementSessionLength = this.incrementSessionLength.bind(this);
    this.decrementSessionLength = this.decrementSessionLength.bind(this);
    this.incrementBreakLength = this.incrementBreakLength.bind(this);
    this.decrementBreakLength = this.decrementBreakLength.bind(this);
    this.fancyTimeFormat = this.fancyTimeFormat.bind(this);
    this.reset = this.reset.bind(this);
  }

  componentDidMount() {
  }

  componentWillUnmount() {
    clearInterval(this.timer);
  }

  toggleTimer() {
    if (this.state.activeTimer === true) {
      clearInterval(this.timer);
      this.setState({ activeTimer: false });
    }
    else {
      this.timer = setInterval(() => {
        if (this.state.sessionSeconds <= 0) {

          document.getElementById("beep").play();

          if (this.state.breakComponentEnabled === false) {
            //No break timer for us; we're done 
            clearInterval(this.timer);
            this.setState({ sessionSeconds: 25, activeTimer: false });
          }
          else {
            if (this.state.breakStarted === false) {
              //By the time this should be executing; we should beginning our break; having completed the session 
              let breakMinutes = this.state.displayBreakMinutes * 60;
              this.setState({ sessionSeconds: breakMinutes, breakStarted: true, activeTimer: true })
            }
            else {
              //By the time this should be executing; we should done; having completed the session and break
              let sessionMinutes = this.state.displayWorkMinutes * 60;
              this.setState({ sessionSeconds: sessionMinutes, activeTimer: false, breakStarted: false });
              if (this.state.runOnce === true) {
                clearInterval(this.timer);
              }
            }

          }
          return;
        }
        this.setState({ sessionSeconds: this.state.sessionSeconds - 1, activeTimer: true });
      }, 1000);
    }
  }



  /**
   * 
   * @param {Number} duration 
   * @returns {String}
   */
  fancyTimeFormat(duration) {
    // Hours, minutes and seconds
    if (duration === 3600) {
      return "60:00";
    }
    var mins = Math.floor((duration % 3600) / 60);
    var secs = Math.floor(duration % 60);

    // Output like "1:01" or "4:03:59" or "123:03:59"
    var ret = "";

    ret += "" + (mins < 10 ? "0" : "") + mins + ":" + (secs < 10 ? "0" : "");
    ret += "" + secs;
    return ret;
  }

  incrementSessionLength() {
    //Increment it by a minute 
    let newLength = this.state.sessionSeconds + 60;
    let newDisplayMinutes = this.state.displayWorkMinutes + 1;
    if (newLength <= 3600) {
      this.setState({ sessionSeconds: newLength, displayWorkMinutes: newDisplayMinutes });
    }
  }

  decrementSessionLength() {
    //Decrement it by a minute 
    let newLength = this.state.sessionSeconds - 60;
    let newDisplayMinutes = this.state.displayWorkMinutes - 1;
    if (newLength > 0) {
      this.setState({ sessionSeconds: newLength, displayWorkMinutes: newDisplayMinutes });
    }
  }


  incrementBreakLength() {
    //Increment it by a minute 
    let newDisplayMinutes = this.state.displayBreakMinutes + 1;
    if (newDisplayMinutes <= 60) {
      this.setState({ displayBreakMinutes: newDisplayMinutes });
    }
  }

  decrementBreakLength() {
    //Decrement it by a minute 
    let newDisplayMinutes = this.state.displayBreakMinutes - 1;
    if (newDisplayMinutes > 0) {
      this.setState({ displayBreakMinutes: newDisplayMinutes });
    }
  }

  reset() {
    this.setState({
      sessionSeconds: 1500,
      activeTimer: false,
      displayWorkMinutes: 25,
      displayBreakMinutes: 5,
      breakComponentEnabled: true,
      breakStarted: false
    });
    document.getElementById("beep").pause();
    document.getElementById("beep").currentTime = 0;
  }

  render() {
    let element = (<p></p>);
    if (this.state.breakComponentEnabled === true) {
      element = (
        <div>
          <p id="break-label">Break length:</p>
          <p id="break-length">{this.state.displayBreakMinutes}</p>
          <button id="break-increment" onClick={this.incrementBreakLength}>+</button>
          <button id="break-decrement" onClick={this.decrementBreakLength}>-</button>
        </div>
      );
    }
    return (
      <div className="App">
        <p id="session-label">Session length:</p>
        <p id="session-length">{this.state.displayWorkMinutes}</p>
        <button id="session-increment" onClick={this.incrementSessionLength}>+</button>
        <button id="session-decrement" onClick={this.decrementSessionLength}>-</button>
        <button id="start_stop" onClick={this.toggleTimer}>
          Toggle timer
        </button>
        <button id="reset" onClick={this.reset}>
          Reset
        </button>
        {element}
        <p id="timer-label">{this.state.breakStarted ? "Break time:" : "Time Left:"}</p>
        <p id="time-left">{this.fancyTimeFormat(this.state.sessionSeconds)}</p>
        <audio id="beep" preload="auto" src="https://raw.githubusercontent.com/freeCodeCamp/cdn/master/build/testable-projects-fcc/audio/BeepSound.wav"></audio>

      </div>
    );
  }
}

export default App;

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0.

Challenge: Build a 25 + 5 Clock

Link to the challenge:

Can you be more specific? Can you provide the repro steps?

Don’t you need to clear the interval on reset? When I do that you only fail #15 which I’m not really sure what’s about.

Step 1: Press the reset button
Step 2: Press the toggle timer button.
Step 3: Press the toggle timer button again to try to get it to stop.
Step 4: Notice the timer is continuing to count down.

Instead of what you have now in reset. Clear the interval after the setState. You can check this.timer before the call to clearInterval.

this.timer && clearInterval(this.timer);

Edit: Just in case it is unclear what I mean.

reset() {
  this.setState({
    sessionSeconds: 1500,
    activeTimer: false,
    displayWorkMinutes: 25,
    displayBreakMinutes: 5,
    breakComponentEnabled: true,
    breakStarted: false,
    runOnce: false
  });

  this.timer && clearInterval(this.timer);

  document.getElementById("beep").pause();
  document.getElementById("beep").currentTime = 0;
}
1 Like

Thank you so much! :smiley:

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.