Reputation: 141
I'm new to ReactJS and I can't seem to find out why the result of the following setState is not as I expect it to be (i.e. to increment the value every second by 1)
import React from 'react';
import ReactDOM from 'react-dom';
class Layout extends React.Component {
constructor() {
super();
this.state = {
name: "Behnam",
i: 0
}
}
render() {
setInterval(() => {
this.setState({ name : "Behnam" + this.state.i });
this.setState({ i: this.state.i + 1 });
}, 1000);
return (
<div className="container">
{this.state.name}
</div>
);
}
}
ReactDOM.render(<Layout />, document.getElementById('app'));
Instead the output string rapidly increases (I guess as fast as react is trying to keep its' virtual DOM updated). So I was wondering what is the right way to do this?
Upvotes: 0
Views: 347
Reputation: 191936
Every time you change the state, you rerender the component.
Because you initiated the setInterval
in the render method, you get another interval, which changes the state, and rerenders, and so on.
Move the setInterval
to componentDidMount, which is invoked only once, when the component mounts:
import React from 'react';
import ReactDOM from 'react-dom';
class Layout extends React.Component {
constructor() {
super();
this.state = {
name: "Behnam",
i: 0
}
}
componentDidMount() { set the interval after the component mounted, and save the reference
this.interval = setInterval(() => {
this.setState({
name: `Behnam${this.state.i}`,
i: this.state.i + 1
});
}, 1000);
}
componentWillUnmount() {
this.interval && clearInterval(this.interval); // clear the interval when the component unmounts
}
render() {
return (
<div className="container">
{this.state.name}
</div>
);
}
}
ReactDOM.render(<Layout />, document.getElementById('app'));
Upvotes: 4
Reputation: 74596
Every time a render is triggered, you're calling setInterval
again, adding to the number of active intervals on the page.
You should perhaps make use of another lifecycle method, such as componentDidMount
. You should remember to save the interval ID returned by setInterval
, so that you can call clearInterval
in componentWillUnmount
.
Upvotes: 1
Reputation: 761
Currently, it is creating an interval every time the component is rendered, so there are multiple timers incrementing the value. You probably want to do it in componentDidMount()
instead of render()
. See docs.
import React from 'react';
import ReactDOM from 'react-dom';
class Layout extends React.Component {
constructor() {
super();
this.state = {
name: "Behnam",
i: 0
}
}
componentDidMount() {
setInterval(() => {
this.setState({ name : "Behnam" + this.state.i });
this.setState({ i: this.state.i + 1 });
}, 1000);
}
render() {
return (
<div className="container">
{this.state.name}
</div>
);
}
}
ReactDOM.render(<Layout />, document.getElementById('app'));
Upvotes: 1