Is setState synchronous or asynchronous?
In fact, setState can appear as an asynchronous update or as a synchronous update
Asynchronous update situation
Life cycle
state = {
number:1
};
componentDidMount(){
this.setState({number:3})
console.log(this.state.number) // The output is the number before update --> 1
}
Copy the code
In a composite event
React encapsulates a set of event mechanisms and proxies for native events, such as onClick and onChange, which are common in JSX.
class App extends Component {
state = { number: 0 }
increment = () = > {
this.setState({ number: this.state.number + 1 })
console.log(this.state.number) // The output is the number before update --> 0
}
render() {
return (
<div onClick={this.increment}>
{`Counter is: ${this.state.number}`}
</div>)}}Copy the code
So what if we want to get the updated value? There are two main methods
Method to get the value of setState updated in real time
The callback function
SetState provides a callback function for developers to use. In the callback function, we can get the updated data in real time
state = {
number:1
};
componentDidMount(){
this.setState({number:3},() = >{
console.log(this.state.number) / / 3})}Copy the code
At this point, you can see that the data printed by the console is up to date, so we can get the latest data in real time.
ComponentDidUpdate Life cycle
class App extends Component {
constructor(props) {
super(props);
this.state = {
number: 0}}render() {
return (
<div>
<h2>Current count: {this.state.number}</h2>
<button onClick={e= >This.changetext ()}> Change the number</button>
</div>)}componentDidUpdate() {
// Method 2: Obtain the state of the asynchronous update
console.log(this.state.number);
}
changeText() {
this.setState({
number:this.state.number + 1}}})Copy the code
Why do asynchronous updates manifest in composite events and life cycles?
It is the performance mechanism of the React framework itself. Because each call to setState triggers an update, asynchronous operations are designed to improve performance by combining multiple states together for updates and reducing render calls.
Imagine executing the following code in a component:
for ( let i = 0; i < 100; i++ ) {
this.setState( { num: this.state.num + 1}); }Copy the code
If setState were a synchronous execution mechanism, the component would be rerendered 100 times, which is a considerable performance drain. React is obviously thinking about this as well, so it made some special optimizations for setState:
React will merge multiple setState calls into one. That is, when setState is executed, the data in the state will not be updated immediately, so the printed value will be the same as the value before the update.
Synchronizing updates
setTimeout
state = {
number:1
};
componentDidMount(){
setTimeout(() = >{
this.setState({number:3})
console.log(this.state.number) / / 3
},0)}Copy the code
In native events
state = {
number:1
};
componentDidMount() {
document.body.addEventListener('click'.this.changeVal, false);
}
changeVal = () = > {
this.setState({
number: 3
})
console.log(this.state.number) / / 3
}
Copy the code
Why are these two cases synchronous updates?
When you setState in a native event, you can get the updated state value at the same time.
SetTimeout can be simply interpreted as skipping the react performance mechanism, so the updated state value can also be synchronized.
Batch updates in setState
export default class App extends Component {
state = {
counter: 0
}
render() {
return (
<div>
<h2>Current count: {this.state.counter}</h2>
<button onClick={e= > this.increment()}>+1</button>
</div>)}increment() {
// 1. SetState itself is merged and does not accumulate, only increments by 1
this.setState({
counter: this.state.counter + 1
});
this.setState({
counter: this.state.counter + 1
});
this.setState({
counter: this.state.counter + 1}); }}Copy the code
- Passing objects directly
setstate
It’s going to be merged once, it’s only going to work once, it’s only going to add one.
The way I write it, it doesn’t merge, it takes effect three times.
this.setState((prevState, props) = > {
return {
counter: prevState.counter + 1}});this.setState((prevState, props) = > {
return {
counter: prevState.counter + 1}});this.setState((prevState, props) = > {
return {
counter: prevState.counter + 1}});Copy the code
conclusion
-
SetState is “asynchronous” in synthesized events and lifecycle functions, and synchronous in native events and setTimeout
-
Callback in the second parameter setState(partialState, callback) can be used to get the updated result. Or get the updated results in the componentDidUpdate lifecycle
-
Multiple setState updates are merged into one, and if any of the same updates are overwritten, only one is executed
Restrict state update views
How do class components limit the update effects of state?
- PureComponent can make a shallow comparison between state and props, and if nothing changes, the component is not updated.
- ShouldComponentUpdate The shouldComponentUpdate lifecycle can determine if the component needs to be updated by checking state changes before and after, and return true if it needs to be updated, false otherwise.