Hello, everyone. I’ve just accepted that because of the way I designed this that some of the tests won’t pass.
However, I’d be grateful for anyone who would take a look at my React code to see if it could be improved in anyway.
A big sticking point for me is that I wanted to add in something to count the sessions so that way the break after the fourth session would be a long break instead of a short one.
It seems like React notices this too late for reasons maybe linked to setState being asynchonous. (It’s just a guess.) I’ve handled this by artificially adding one for computing purposes, but I’d like to know if there’s a more… idiomatic (?) or efficient way to do this. You can see what I mean on line 185.
Just as a note, the short break and session are set as one second and the long break as one minute just to make testing easier.
Thanks in advance.
https://codepen.io/donthatedontkill/pen/vzvKrr?editors=0010
function setStateCounter(num){
return(previousState) =>{return {...previousState, counter: previousState.counter + num}}
}
/* Timer display filter */
class Display extends React.Component{
constructor(props){
super(props);
this.addZero = this.addZero.bind(this)
}
addZero(num){
if (num < 10){
return ("0" + num)
}
else{
return num
}
}
render(){
return(
<div>{this.addZero(this.props.minutes)}:{this.addZero(this.props.seconds)}</div>
);
}
}
/*Timer architecture */
class Timer extends React.Component{
constructor(props){
super(props);
this.state = {
minutes: this.props.minutes,
seconds: 1,
timerOn: false,
html: {
length: this.props.type +"-length",
label: this.props.type +"-label",
decrement: this.props.type +"-decrement",
increment: this.props.type +"-increment"
},
}
this.TimerFunction = this.TimerFunction.bind(this);
this.activateTimer = this.activateTimer.bind(this);
this.reset = this.reset.bind(this);
this.increaseMinutes = this.increaseMinutes.bind(this);
this.decreaseMinutes = this.decreaseMinutes.bind(this);
}
/*Buttons for changing the time limit*/
increaseMinutes(){
if (this.state.timerOn == false && this.state.minutes < 60){
this.setState({
minutes: this.state.minutes + 1,
})}
}
decreaseMinutes(){
if (this.state.timerOn == false && this.state.minutes > 0){
this.setState({
minutes: this.state.minutes - 1,
})}}
/*Timer mechanism*/
TimerFunction(){
if (this.state.minutes > 0 || this.state.seconds > 0){
if (this.state.seconds <= 0){
this.setState({
minutes: this.state.minutes - 1,
seconds: 59,
})
}
else{
this.setState({
seconds: this.state.seconds - 1
})
}
}
else{
clearInterval(this.timerInterval);
this.setState({
timerOn: false,
minutes: this.props.minutes,
seconds: 1,
})
this.props.timerSwitch(this.props.type);
this.props.counterUp();
}
}
/*Start/pause button */
activateTimer(){
if (this.state.timerOn == false){
this.setState({
timerOn: true
})
this.timerInterval = setInterval(this.TimerFunction, 1000)
}
if (this.state.timerOn == true){
this.setState({
timerOn: false,
})
clearInterval(this.timerInterval)
}
}
/*Reset button*/
reset(){
clearInterval(this.timerInterval)
this.setState({
minutes: this.props.minutes,
seconds: 0,
timerOn: false,
})
this.props.reset()
}
render(){
return(
<div id='timer'>
<div id={this.state.html.label}>
{this.props.type} Length: </div>
<div id={this.state.html.length}>
{this.state.minutes}</div>
<button onClick={this.increaseMinutes} id={this.state.html.increment}>Increase session minutes</button>
<button onClick={this.decreaseMinutes} id={this.state.html.decrement}>Decrease session minutes</button>
{(this.props.active===this.props.type) && <div id="time-left"><Display minutes={this.state.minutes} seconds={this.state.seconds}/><button id="start_stop" onClick={this.activateTimer}>Click me</button> <button onClick={this.reset}>Reset</button></div>}
</div>
)
}
}
class App extends React.Component{
constructor(props){
super(props);
this.state = {
currentTimer: "session",
defaultSession: 0,
shortBreak: 0,
longBreak: 1,
counter: 0,
}
this.changeTimer = this.changeTimer.bind(this);
this.reset = this.reset.bind(this);
this.counterUp = this.counterUp.bind(this);
}
changeTimer(finishedTimer){
if (finishedTimer == "session"){
this.setState({
currentTimer: "break",
}
)
}
if (finishedTimer == "break"){
this.setState({
currentTimer: "session",
})
}
}
reset(){
this.setState({
currentTimer: "session",
})
}
/*Attempt to fix async issue with timer*/
counterUp(){
this.setState(setStateCounter(1))
}
render(){
return(
<div>
{(this.state.counter % 4)}
<div id="timer-label">{this.state.currentTimer} initiated</div>
<Timer type="session" minutes={this.state.defaultSession} active={this.state.currentTimer} timerSwitch={this.changeTimer} reset={this.reset} counterUp={this.counterUp}/>
{this.state.counter}
<Timer type="break" minutes={((this.state.counter+1) < 4 || (this.state.counter+1) % 4 != 0) ? this.state.shortBreak : this.state.longBreak} active={this.state.currentTimer} timerSwitch={this.changeTimer} reset={this.reset}/>
</div>
)}
};
ReactDOM.render(
<App />,
document.getElementById('root')
);