The worm The worm - 5 days ago 4
Javascript Question

Countdown timer in React

I have seen lots of countdown timers in JavaScript and wanted to get one working in React.

I have borrowed this function I found online:

secondsToTime(secs){
let hours = Math.floor(secs / (60 * 60));

let divisor_for_minutes = secs % (60 * 60);
let minutes = Math.floor(divisor_for_minutes / 60);

let divisor_for_seconds = divisor_for_minutes % 60;
let seconds = Math.ceil(divisor_for_seconds);

let obj = {
"h": hours,
"m": minutes,
"s": seconds
};
return obj;
};


And then I have written this code myself

initiateTimer = () => {
let timeLeftVar = this.secondsToTime(60);
this.setState({ timeLeft: timeLeftVar })
};

startTimer = () => {
let interval = setInterval(this.timer, 1000);
this.setState({ interval: interval });
};

timer = () => {
if (this.state.timeLeft >0){
this.setState({ timeLeft: this.state.timeLeft -1 });
}
else {
clearInterval(this.state.interval);
//this.postToSlack();
}
};


Currently onclick it will set the time on screen to:
Time Remaining: 1 m : 0 s

But it does not reduce it to
Time Remaining: 0 m : 59 s
and then
Time Remaining: 0 m : 58 s
etc etc

I think I need to call the function again with a different parameter. how can I go about doing this ?

EDIT: I FORGOT TO SAY, I WOULD LIKE THE FUNCTIONALITY SO THAT I CAN USE SECONDS TO MINUTES & SECONDS

Answer

You have to setState every second with the seconds remaining (every time the interval is called). Here's an example:

class Example extends React.Component {
  constructor() {
    super();
    this.state = { time: {}, seconds: 5 };
    this.timer = 0;
    this.startTimer = this.startTimer.bind(this);
    this.countDown = this.countDown.bind(this);
  }

  secondsToTime(secs){
    let hours = Math.floor(secs / (60 * 60));

    let divisor_for_minutes = secs % (60 * 60);
    let minutes = Math.floor(divisor_for_minutes / 60);

    let divisor_for_seconds = divisor_for_minutes % 60;
    let seconds = Math.ceil(divisor_for_seconds);

    let obj = {
      "h": hours,
      "m": minutes,
      "s": seconds
    };
    return obj;
  }

  componentDidMount() {
    let timeLeftVar = this.secondsToTime(this.state.seconds);
    this.setState({ time: timeLeftVar });
  }

  startTimer() {
    if (this.timer == 0) {
      this.timer = setInterval(this.countDown, 1000);
    }
  }

  countDown() {
    // Remove one second, set state so a re-render happens.
    let seconds = this.state.seconds - 1;
    this.setState({
      time: this.secondsToTime(seconds),
      seconds: seconds,
    });
    
    // Check if we're at zero.
    if (seconds == 0) { 
      clearInterval(this.timer);
    }
  }

  render() {
    return(
      <div>
        <button onClick={this.startTimer}>Start</button>
        m: {this.state.time.m} s: {this.state.time.s}
      </div>
    );
  }
}

ReactDOM.render(<Example/>, document.getElementById('View'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="View"></div>

Comments