preface
Before React16.8, React accessed state via this.state and updated state via the this.setState() method. When this.setstate () is called, React recalls the render method to rerender the UI. State is an important concept in React. React manages components through state management. How does React control component state and manage components using state?
1. In the composite eventsetState
The common onClick and onChange events in JSX are synthetic events
class App extends Component { state = { val: 0 } increment = () => { this.setState({ val: Val console.log(this.state.val) // 0} render() {return (<div onClick={this.increment}> {`Counter is: ${this.state.val}`} </div> ) } }Copy the code
When you go to console.log in Increment after you call setState in Increment, it’s part of the try block, but since it’s a composite event, the state is not updated after the try block executes, so you enter the value of the state before the update. This results in what is called “asynchron”, but when your try block is finished (which is your increment synthesis event), then you execute the finally code, which executes the performSyncWork method, This is when you update your state and render it to the UI.
Ii. In the life cycle functionsetState
class App extends Component { state = { val: 0 } componentDidMount() { this.setState({ val: Console.log (this.state.val) // 0} render() {return (<div> {' Counter is: ${this.state.val}`} </div> ) } }Copy the code
CommitUpdateQueue (commitUpdateQueue) updates componentDidmount (componentDidmount) after componentDidmount (commitUpdateQueue) This causes you to setState componentDidmount and go to console.log to get the same value as before.
3. In native eventssetState
class App extends Component { state = { val: 0 } changeValue = () => { this.setState({ val: This.state. val + 1}) // Output the updated value!! console.log(this.state.val) // 1 } componentDidMount() { document.body.addEventListener('click', this.changeValue, false) } render() { return ( <div> {`Counter is: ${this.state.val}`} </div> ) } }Copy the code
Native events are non-react synthesized events, native event listener addEventListener, or binding events in the form of native JS, jQ direct document.querySelector().onclick.
If you have a requestWork context === Sync you would like a requestWork context. If you have a requestWork context === Sync you would like a requestWork context. If you have a requestWork context you would like a requestWork context. It’s not as if the synthesized event or the hook function is returned, so when you setState in the native event, you can get the updated state value synchronously.
Four,setTimeout
In thesetState
class App extends Component { state = { val: 0 } componentDidMount() { setTimeout(_ => { this.setState({ val: Console.log (this.state.val) // 1}, 0)} render() {return (<div> {' Counter is: ${this.state.val}`} </div> ) } }Copy the code
SetState is not a separate scene in setTimeout, it’s determined by your outer layer, because you can setTimeout in a synthetic event, you can setTimeout in a hook function, you can setTimeout in a native event, However, no matter in which scenario, based on the event loop model, setState in setTimeout can always get the latest state value.
Five,setState
Batch update in
class App extends Component {
state = { val: 0 }
batchUpdates = () => {
this.setState({ val: this.state.val + 1 })
this.setState({ val: this.state.val + 1 })
this.setState({ val: this.state.val + 1 })
}
render() {
return (
<div onClick={this.batchUpdates}>
{`Counter is ${this.state.val}`} // 1
</div>
)
}
}
Copy the code
React creates an updateQueue internally during setState and maintains a queue of updates via firstUpdate, lastUpdate, lastupdate. next. In the final performWork, The same key will be overwritten, and only the last setState will be updated.
class App extends React.Component {
state = { val: 0 }
componentDidMount() {
this.setState({ val: this.state.val + 1 })
console.log(this.state.val)
this.setState({ val: this.state.val + 1 })
console.log(this.state.val)
setTimeout(_ => {
this.setState({ val: this.state.val + 1 })
console.log(this.state.val);
this.setState({ val: this.state.val + 1 })
console.log(this.state.val)
}, 0)
}
render() {
return <div>{this.state.val}</div>
}
}
Copy the code
As shown above, setState in the hook function can’t get the updated value immediately, so the first two times are output 0. When the setTimeout is executed, the values of the first two states have been updated. Because setState updates in batches, This.state. val is valid only for the last time, which is 1. In setTimmout, setState can be synchronized to the update result, so the two outputs of setTimeout, 2, 3, will result in 0, 0, 2, 3.
conclusion
setState
It is “asynchronous” only in synthetic events and hook functions, and in native events andsetTimeout
Is in sync.setState
“Asynchronous” is not to say within the asynchronous code implementation, execution process and actually are synchronized code, just synthetic events and hook function call order before update, resulting in synthetic events and hook function can not immediately get the updated value, form the so-called “asynchronous”, can, of course, by the second argumentsetState(partialState, callback)
In thecallback
Get the updated results.setState
The batch update optimization is also built on “asynchronous” (synthetic events, hook functions), in native events andsetTimeout
Do not batch update, in “asynchronous” if the same value multiple timessetState
.setState
The batch update policy will override it and take the last execution, if it is at the same timesetState
Multiple different values, which will be consolidated for batch update when updated.