State
There are two types of data that control a component: props
and state
. props
are set by the parent and they are fixed throughout the lifetime of a component. For data that is going to change, we have to use state
.
In general, you should initialize state
in the constructor, and then call setState
when you want to change it.
Adding Local State to a Class
Use this.state
in the render()
method. Add a class constructor that assigns the initial this.state
.
class Welcome extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return <h1>Hello, {this.state.name}</h1>;
}
}
this.setState
There are three things you should know aboutsetState()
.
Do Not Modify State Directly
For example, this will not re-render a component:
// Wrong
this.state.comment = 'Hello';
Instead, use setState()
:
// Correct
this.setState({comment: 'Hello'});
The only place where you can assign this.state
is the constructor.
State Updates May Be Asynchronous
React may batch multiple setState()
calls into a single update for performance.
Because this.props
and this.state
may be updated asynchronously, you should not rely on their values for calculating the next state.
For example, this code may fail to update the counter:
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
To fix it, use a second form of setState()
that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
// Correct
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
We used an arrow function above, but it also works with regular functions:
// Correct
this.setState(function(prevState, props) {
return {
counter: prevState.counter + props.increment
};
});
State Updates are Merged
When you call setState()
, React merges the object you provide into the current state.
For example, your state may contain several independent variables:
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
}
Then you can update them independently with separatesetState()
calls:
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
The merging is shallow, so this.setState({comments})
leaves this.state.posts
intact, but completely replaces this.state.comments
.