About
state management in class component
In React, mutable state is typically kept in the state property of components, and only updated with setState().
Articles Related
Rules
- Do Not Modify State Directly. Use this.setState(). The only place where you can assign this.state is the constructor.
- Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.
Wrong, this code may fail to update the counter.
this.setState({
counter: this.state.counter + this.props.increment,
});
Correct. Passes a function rather than an object.
this.setState(function(prevState, props) {
return {
counter: prevState.counter + props.increment
};
});
// or with the arrow function notation
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
- setState() merges the object you provide into the current state. You can update several props independently with separate setState() calls (ie setState calls are batched). The merging is shallow, so this.setState({comments}) leaves all other props intact (this.state.*) but completely replaces this.state.comments.
- Neither parent nor child components can know if a certain component is stateful or stateless, and they shouldn't care whether it is defined as a function or a class. This is why state is often called local or encapsulated. It is not accessible to any component other than the one that owns and sets it.
- A component may choose to pass its state down as props to its child components. This is commonly called a “top-down” or “unidirectional” data flow. Any state is always owned by some specific component, and any data or UI derived from that state can only affect components “below” them in the tree.
Process
- React may batch multiple setState() calls into a single update for performance.
Shared State
When a state is shared between components, the common technique is lifting up the state to their closest common ancestor. See React Class Component - Shared State (Lifting state up)
Example
- The Clock components with state using the lifecycle functions componentWillUnmount and componentDidMount. See React Class Component - Rendering (Mounting/Unmounting)
class Clock extends React.Component {
// Since Clock needs to display the current time, the constructor initializes this.state
constructor(props) {
super(props);
this.state = {date: new Date()};
}
// When the Clock output is inserted in the DOM, React calls the componentDidMount() lifecycle hook.
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
// Called if the Clock component is ever removed from the DOM, so the timer is stopped.
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
// Thanks to the setState() call, React knows the state has changed, and calls render() method again.
this.setState({
date: new Date()
});
}
// React learns what should be displayed on the screen.
// React then updates the DOM to match the Clock's render output.
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
- The classic Render and XML function. When <Clock /> is passed to ReactDOM.render(), React calls the constructor of the Clock component, then calls the Clock component's render() method.
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
<div id="root">
<!-- called the "root" DOM node because everything inside it will be managed by React DOM -->
</div>