Reputation: 397
I'm currently working on a simple stopwatch application using react, and I'm have some issues updating the secondsPassed prop when the start button is clicked. I'm currently getting the error:
TypeError: Cannot set property 'counter' of undefined
The error is occurring in the handleStart event. I defined thisStart to have the scope of the handleStart event. I believe I defined the variable counter in the constructor and I'm trying to update that counter by incrementing the seconds passed by 1
import React, { Component } from 'react';
import '../assests/stopwatch.css';
class StopWatch extends Component {
// handle state
constructor(props) {
super(props);
this.state = {
secondsPassed: 0,
counter: 0
};
}
// define event functions for start, pause and reset
handleStart() {
let thisStart = this;
this.counter = setInterval(() => {
thisStart.setState({
secondsPassed: (thisStart.state.secondsPassed + 1)
});
}, 1000)
}
handlePause() {
clearInterval(this.counter);
}
handleReset() {
this.getInitialState()
}
// define function that shows the seconds passed
// the initial state is going to be zero
getInitialState() {
return { secondsPassed: 0 };
}
getSeconds() {
return ('0' + this.state.secondsPassed % 60).slice(-2);
}
getMinutes() {
return Math.floor(this.state.secondsPassed / 60);
}
render() {
return (
<React.Fragment>
<div id="container">
<h1>Stopwatch APP</h1>
<div id="stopwatch-container">
<div className="time-container">
<span>{this.getMinutes()}:{this.getSeconds()}</span>
</div>
<div className="button-container">
<div className="start-button">
<button type="button" onClick={this.handleStart}>Start</button>
</div>
<div className="pause-button">
<button type="button" onClick={this.handlePause}>Pause</button>
</div>
<div className="reset-button">
<button type="button" onClick={this.handleReset}>Reset</button>
</div>
</div>
</div>
</div>
</React.Fragment >
);
}
}
export default StopWatch;
Upvotes: 0
Views: 482
Reputation: 2361
I assume you define this.counter in handleStart because you want to use it as a id for clearInterval ,but I think you should this.state.counter instead of this.counter,and you didn't bind the function in constructor ,it will lead to some problems.
constructor(props) {
super(props);
this.handleStart = this.handleStart.bind(this)
this.handlePause = this.handlePause.bind(this)
this.getInitialState = this.getInitialState.bind(this)
this.handleReset = this.handleReset.bind(this)
this.state = {
secondsPassed: 0,
counter: 0
};
}
...
handleStart() {
this.state.counter = setInterval(() => {
this.setState({
secondsPassed: this.state.secondsPassed + 1
})
},1000)
}
handlePause() {
clearInterval(this.state.counter);
}
BTW, I think the return in getInitialState make no sense,it should use setState
getInitialState() {
// return { secondsPassed: 0 };
this.setState({
secondsPassed: 0
})
}
Upvotes: 1
Reputation: 526
¿counter will be a variable or a function? He's looking for a global property called counter. The correct way to assign states is:
this.setState( obj );
Where obj is your object. I don't understand why you use 'this.state.secondsPassed' but with counter just 'this.counter' when it'll should be the same.
Read these two articles talking about React States and Lifecycle (also contains a timer function) so you can first clarify your current understanding.
EDIT: Perhaps you're trying to use counter and secondsPassed re-using their values, for that case you could use the parameter sent to setState:
this.setState( (previousState) => {
previousState.counter = 0;
return previousState;
}
Here, we're just using the previous value of secondsPassed with a new one for counter.
Upvotes: 1
Reputation: 517
you should bind the callbacks. either in the JSX use
<button ... onClick={this.handleStart.bind(this)}...>
or in the constructor
constructor () {
super(props);
this.handleStart = this.handleStart.bind(this);
// do this for the rest of the functions
}
You don't need to create a custom scope for the interval function, simple arrow function will do the trick.
Upvotes: 1