How do I get the value after setState
Methods a
Class Demo extends Component {state = {isActive: false} handleClick1(){this.setState({isActive: false); true }, () => { console.log(this.state.isActive) // true }) console.log(this.state.isActive) // false } // HandleClick2 (){this.setState((prevState, props) => {isActive:! prevState.isActive }, () => {console.log(this.state.isactive) // true -> first click}) console.log(this.state.isactive) // false -> first click} render(){ return( <> <button onClick={handleClick1}></button> </> ) } }Copy the code
Method 2
class Demo extends Component {
state = {
isActive: false
}
async handleClick(){
await this.setState({
isActive: true
})
console.log(this.state.isActive) // true
}
render(){
return(
<>
<button onClick={handleClick}></button>
</>
)
}
}
Copy the code
Why can’t we update the data with this.state.XXX= new value?
When setState is executed, the state that needs to be updated will be merged and put into the status queue instead of updating this.state immediately. The queuing mechanism can efficiently update the state in batches. If this.state.XXX= new value is directly used instead of setState, then the changed state will not be put into the state queue. When setState is called next time and the state queue is merged, the previously directly modified state will be ignored, resulting in unpredictable errors.
Update mechanism for setState
Let’s start with some code
import React, { Component } from 'react';
class Counter extends Component{
state = {count : 0}
incrementCount = () => {
this.setState({count : this.state.count + 1})
this.setState({count : this.state.count + 1})
}
render(){
return <div>
<button onClick={this.incrementCount}>Increment</button>
<div>{this.state.count}</div>
</div>
}
}
export default Counter;
Copy the code
Cut into the topic
When setState is called, the new state goes into a state queue, and the same operation is merged. React makes a shallow copy of the new value.
Object.assign(
previousState,
{count : state.count + 1},
{count : state.count + 1}
)
Copy the code
After that, the enqueueUpdate method is called to determine whether to update components in batch mode with isBatchingUpdates.
Whether setState is asynchronous or synchronous
emphasis
SetState is not really asynchronous, it just looks asynchronous. In the source code, check by isBatchingUpdates
SetState is either stored in the state queue first or updated directly, asynchronously if true, or updated directly if false.
scenario
True where React can be controlled, such as in React lifecycle events and composited events, both merge and delay updates.
However, when React is out of control, such as native events, such as addEventListener, setTimeout, setInterval, etc., updates can only be synchronized.
So why asynchronous operations?
1. It is generally accepted that asynchronous design is done for performance optimization and reduced rendering times
2. Maintain internal consistency. If you change state to synchronous update, though the update to state is synchronous, the props is not.
First, I think we can all agree that delaying and batching rerenders is beneficial and important for performance optimization, regardless of whether setState() is synchronous or asynchronous. So even if you update state synchronously, you don’t know props until the parent re-renders.
Assuming state is updated synchronously, the following code works as expected:
console.log(this.state.value) // 0 this.setState({ value: this.state.value + 1 }); console.log(this.state.value) // 1 this.setState({ value: this.state.value + 1 }); Console. log(this.state.value) // 2 Copies the codeCopy the code
However, at this point you need to promote the state to the parent component for multiple sibling components to share:
-this.setState({ value: this.state.value + 1 }); +this.props.onIncrement(); // Do the same thing in the parent component to copy the codeCopy the code
It should be noted that this is a very common refactoring in React applications and happens almost every day.
However, the following code does not work as expected:
console.log(this.props.value) // 0 this.props.onIncrement(); console.log(this.props.value) // 0 this.props.onIncrement(); Console. log(this.props. Value) // 0 Copies the codeCopy the code
This is because in the synchronous model, although this.state is updated immediately, this.props is not. And we can’t update this.props immediately without re-rendering the parent component. If you wanted to update this.props immediately (i.e., rerender the parent component immediately), you would have to give up batch processing (which, depending on the situation, could have a significant performance degradation).
In React, both this.state and this.props are updated asynchronously. In the example above, 0 is printed before and after refactoring. This will make the state lift safer.
Finally, the React model prefers to ensure internal consistency and state-enhanced security, rather than always pursuing code simplicity.