Reputation: 523
I'm trying to build a React component that has two timers. The first one is three seconds, and when it hits zero it says "GO!" then immediately starts the next one, which is a 60 second timer. I got all of this to work, but I can't figure out how to stop the 60 second timer from starting over when it hits zero. Ideally I will be splitting these into two components once I figure this out, but right now I just want to get everything to work properly. Can someone steer me in the right direction here?
import React, { Component } from "react";
import ReactDOM from "react-dom"
class Countdown extends React.Component {
constructor(props) {
super(props);
this.state = { time: {}, seconds: 3 };
this.timer = 0;
this.startTimer = this.startTimer.bind(this);
this.countdown = this.countdown.bind(this);
}
formatSeconds (totalSeconds) {
let seconds = totalSeconds;
let minutes = Math.floor(totalSeconds / 60);
if (seconds < 10) {
seconds = '0' + seconds;
}
if (minutes < 10) {
minutes = '0' + minutes;
}
let obj = {
"minutes": minutes,
"seconds": seconds
};
return obj;
}
componentDidMount() {
let timeLeft = this.formatSeconds(this.state.seconds);
this.setState({ time: timeLeft });
}
startTimer() {
if (this.timer === 0) {
this.timer = setInterval(this.countdown, 1000);
}
}
countdown() {
let seconds = this.state.seconds - 1;
this.setState({
time: this.formatSeconds(seconds),
seconds: seconds
});
if (seconds === 0) {
clearInterval(this.timer);
let element = (
<h2>GO!</h2>
);
ReactDOM.render(
element,
document.getElementById('go')
);
this.state.seconds = 61;
let seconds = this.state.seconds - 1;
this.timer = setInterval(this.countdown, 1000);
this.setState({
time: this.formatSeconds(seconds),
seconds: seconds
});
// how do I stop the second timer from looping?
}
}
render() {
return(
<div className="container">
<div className="row">
<div className="column small-centered medium-6 large-4">
<h2 id="go"></h2>
{this.state.time.seconds}<br />
<button className="button" onClick={this.startTimer}>Start</button>
</div>
</div>
</div>
);
}
}
export default Countdown;
Upvotes: 0
Views: 2090
Reputation: 6482
Could you break it out into two countdown functions as follows?
class Countdown extends React.Component {
constructor(props) {
super(props);
this.state = {
countdownSeconds: 3,
roundSeconds: 60
};
this.countdown = this.countdown.bind(this);
this.roundCountdown = this.roundCountdown.bind(this);
this.startTimer = this.startTimer.bind(this);
}
startTimer() {
if(!this.countdownTimer) {
this.countdownTimer = setInterval(this.countdown, 1000);
}
}
countdown() {
const currentSeconds = this.state.countdownSeconds - 1;
this.setState({
countdownSeconds: currentSeconds
});
if(currentSeconds === 0) {
this.roundTimer = setInterval(this.roundCountdown, 1000);
clearInterval(this.countdownTimer);
}
}
roundCountdown() {
const currentSeconds = this.state.roundSeconds - 1;
this.setState({
roundSeconds: currentSeconds
});
if(currentSeconds === 0) {
//do whatever
clearInterval(this.roundTimer);
}
}
}
Edit:
If I understand your other question, to display the appropriate countdown you could maybe do something like
render() {
const { countdownSeconds, roundSeconds } = this.state;
return (
<div>
{countdownSeconds > 0 &&
<span>Counting down...{countdownSeconds}</span>
}
{roundSeconds > 0 && countdownSeconds === 0 &&
<span>Round underway...{roundSeconds}</span>
}
</div>
);
}
Or you could functionalize the rendering of the the timer, i.e.
renderTimer() {
const { countdownSeconds, roundSeconds } = this.state;
if(countdownSeconds > 0) {
return <span>Counting down...{countdownSeconds}</span>;
}
return <span>Round underway...{roundSeconds}</span>;
}
and then:
render() {
return (
<div>
{this.renderTimer()}
</div>
);
}
Upvotes: 1