Reputation: 351
I'm having some issues using setInterval with React.
Basically, I'm trying to build a Pomodoro timer for FreeCodeCamp, and setInterval is not recognizing that the function is defined.. link below.
https://codepen.io/paalpwmd/pen/yLNJEMv?editors=1111
Basically - I want the timer method to subtract 1000ms from the total length state until the the length is 0.
The error I get is this..
TypeError: this.tick is not a function
at https://cdpn.io/boomboom/v2/index.html?editors=1111&key=iFrameKey-713a6d83-4480-ba30-a898-c7e72b527740:28
I've also tried putting the set interval function directly inside the timer (like this), and I get an error saying that this.state is undefined.
timer(){
setInterval(function() {
this.setState({
length: this.state.length - 1000
}), 1000)
}
I've tried both ES6 and ES5 syntax, and this is bound at the constructor.
I assume that this has something to do with the way that React binds this. What am I doing wrong here?
Upvotes: 1
Views: 133
Reputation: 10569
Change the setInterval
callback function
to arrow function
.
when the setInterval
will call the callback function the this
will refer to the setInterval object
.
Always use the
callback
in the setState if the state update depends on the previous state.
Try this.
timer() {
setInterval(() => {
this.tick();
console.log("tick");
}, 1000)
}
Working Example:
class PomTimer extends React.Component {
constructor(props) {
super(props)
this.state = {
break: 300000,
length: 1500000,
clockFace: ''
}
this.clockify = this.clockify.bind(this);
this.timer = this.timer.bind(this);
this.reset = this.reset.bind(this);
this.tick = this.tick.bind(this);
}
reset() {
this.setState({
break: 300000,
length: 1500000
})
this.clockify();
}
tick() {
//console.log("tick: " + this.state.length);
if (this.state.length > 0) {
this.setState( (preState) => {
return {
length: preState.length - 1000
}
})
} else {
}
}
clockify() {
let minutes = Math.floor(this.state.length / 60000);
let seconds = (this.state.length % 60000) / 1000
this.setState({
clockFace: `${minutes}:${seconds}`
})
}
timer() {
setInterval(() => {
this.tick();
}, 1000)
}
componentDidMount() {
this.clockify();
}
render() {
return <div>
<h1>Pomodoro Clock</h1>
<div id="break-label">
<div id="break-increment" onClick={this.breakInc}>+</div>
<p id="break-length">Break Length: {this.state.break / 60000}</p>
<div id="break-decrement" onClick={this.breakDec}>-</div>
</div>
<div id="session-label">
<div id="session-increment" onClick={this.sessionInc}> + </div>
<p id="session-length">Session Length {Math.ceil(this.state.length / 60000)} ({this.state.length})</p>
<div id="session-decrement" onClick={this.sessionDec}> - </div>
</div>
<div id="session">
<p id="time-left"> Session: {this.state.clockFace} </p>
</div>
<button onClick={this.clockify}>test</button>
<button onClick={this.resetTimer}>Reset</button>
<button onClick={this.timer}>Timer</button>
</div>
}
}
ReactDOM.render(<PomTimer />, document.getElementById("react-root"));
#react-root {
width: 50%;
display: flex;
margin: auto;
border: 2px solid black;
border-radius: 50px;
justify-content: center;
}
body {
background-color: #1E555C;
font-family: 'Verdana'
}
#break-increment, #break-decrement, #session-increment, #session-decrement{
cursor: pointer;
margin: 0px 5px;
border: 1px solid black;
border-radius: 5px;
width: 20px;
height: 20px;
text-align: center;
background-color: #1E777C;
}
#session-label, #break-label, #session {
display: flex;
flex-direction: row;
justify-content: center;
padding-top: 50px;
}
#break-length, #session-length{
margin: 0;
}
#time-left {
font-size: 2rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react-root">
Upvotes: 1