Reputation: 231
Learning ReactJS I am working on a simple countdown app. The Countdown component looks like this:
const Countdown = React.createClass({
getInitialState: function() {
return {
remaining: 10,
running: true,
};
},
componentDidMount: function(){
if (this.state.running) {
setInterval(this.tick, 1000);
} else {
console.log("already paused");
};
},
tick: function(){
if (this.state.remaining === 0) {
this.setState({ remaining: 10 });
this.props.updateStats();
} else {
this.setState({ remaining: this.state.remaining -1 });
};
},
handlePauseClick: function(){
this.setState({ running: false });
},
render: function(){
const s = this.state.remaining;
return (
<div className='ui centered card'>
<div className='content centered'>
<h1>{helpers.secondsToHuman(s)}</h1>
<ButtonControls
handlePauseClick={this.handlePauseClick}
/>
</div>
</div>
)
},
});
The countdown starts running. When clicking on the pause button it is supposed to stop. The componentDidMount only runs the timer when running is true:
if (this.state.running) {
setInterval(this.tick, 1000);
} else {
console.log("already paused");
};
After handling the click with:
this.setState({ running: false });
I was expecting that the component gets re-rendered and that componentDidMount will be executed again. This is not happening though. componentDidMount seems only to run once.
Thanks for your ideas
Upvotes: 7
Views: 3953
Reputation: 20027
componentDidMount gets executed only once, when the React component is mounted to the tree, that's why it is not called after setState
.
So you need componentDidUpdate, this callback gets executed on every rerender except for the initial one. For the initial one you may want to use componentDidMount.
Also, you are not clearing the interval in the else
block, which means that the tick
function will not stop executing even if the component is rerendered again.
Try this
componentDidMount: function() {
this.tickInterval = setInterval(this.tick, 1000);
},
componentDidUpdate: function() {
// if app is running and there is no tickInterval yet, set it
if (this.state.running && this.tickInterval === null) {
this.tickInterval = setInterval(this.tick, 1000);
// if app is stopped, but there is a tickInterval, clear it
} else if (!this.state.running && this.tickInterval !== null) {
clearInterval(this.tickInterval);
this.tickInterval = null;
}
},
componentWillUnmount() {
clearInterval(this.tickInterval);
}
Upvotes: 14
Reputation:
componentDidMount
is only executed when the initial render process is finished. You should use componentWillUpdate
or componentDidUpdate
for your task.
Upvotes: 1