React document:

  1. Do not modify state directly
  2. Updates to state can be asynchronous
  3. State updates are merged

Do not modify state directly

The documentation doesn’t explain why, except that the constructor is the only place where you can assign state directly.

Possible causes:

  • Collection state changes

Data-driven frame mode: State changes –> View changes automatically.

A common operation to change state is a direct assignment; The other is the function setxxx.

Vue uses Object.defineProperty and proxy to listen on objects and achieve state collection.

There is no dependency collection in React, so direct assignments do not allow React to listen for state changes.

  • Better maintenance of immutable data.

SetState internally actually returns a new state. If you change state directly, there are a number of nasty side effects (poor readability, unpredictable bugs).

Const person = {player: {name: '456'}}; const person1 = person; Person.player. name = 123 // var == let const Reduce the side effects of VARCopy the code

Only pure functions without side effects are qualified functions.

  • To update state in a unified manner, which is conducive to maintenance and control;

A fixed setState function makes the entire render/update process more manageable, including various performance optimizations (diff, persistent data structures).

Second, state updates can be asynchronous

Asynchronous? Which is macro task, micro task category?

Test case

Case study:

HandleClick () {const base = 5 setTimeout(() => {console.log(' macro task triggered ')}, 0) promise.resolve ().then(()=>{console.log(' microtask trigger ')}) this.setState({count: This.state.count + base}, () => {console.log(' updated value: ', this.state.count)}) console.log('methods end'); } // Execute the result, SetState precedes microtask handleClick2() {setTimeout(()=>{const base = 5 setTimeout(()=>{console.log(' macro task triggers 2')}, 0) promise.resolve ().then(()=>{console.log(' microtask trigger 2')}) this.setState({count: This.state.count + base}, () => {console.log(' console.log ', this.state.count)}) console.log('methods end2'); }, 10)} // Perform setState synchronization (" 5 ")Copy the code

SetState itself is not asynchronous, but it is handled asynchronously by the React performance optimization mechanism

Conclusion:

  • In the component life cycle or React composite event, setState is asynchronous;

In the React lifecycle and bound event flow, all setState operations are cached in a queue. After the event is over, the queue is removed to trigger state updates.

  • In setTimeout or native DOM events, setState is synchronous;

State updates will be merged

A State change means that the component is rerendered. To optimize performance, React collects state changes and only executes render once in case of multiple calls.

Case study:

MergeState () {for (let I = 0; i < 10; i++ ) { this.setState( { count: this.state.count + 1 } , () => { console.log(this.state.count) }); } // count = 1 for (let I = 0; i < 10; I++) {this.setstate (prevState => {// prevSate last state console.log(prevstate.count); return { count: prevState.count + 1 } } ); } // count is 10} // description: // 1. The setstate of the directly passed object is merged into one // 2. Passing state using functions will not be mergedCopy the code

One last demo:

Val number 0 demo(){this.setState({val: this.state.val + 1}); Console. log('== first output ==', this.state.val); This.setstate ({val: this.state.val + 1}); Console. log('== second output ==', this.state.val); SetTimeout (() => {this.setState({val: this.state.val + 1}); Console. log('== third output ==', this.state.val); This.setstate ({val: this.state.val + 1}); Console. log('== fourth output ==', this.state.val); }, 0); } // 0 0 2 3Copy the code

Figure 3-15 Shows In Depth on the React Technology Stack

The source code

Decryption setState