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,setTimeoutIn 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,setStateBatch 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

  1. setStateIt is “asynchronous” only in synthetic events and hook functions, and in native events andsetTimeoutIs in sync.
  2. 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 thecallbackGet the updated results.
  3. setStateThe batch update optimization is also built on “asynchronous” (synthetic events, hook functions), in native events andsetTimeoutDo not batch update, in “asynchronous” if the same value multiple timessetState .setStateThe batch update policy will override it and take the last execution, if it is at the same timesetStateMultiple different values, which will be consolidated for batch update when updated.