react advanced Lecture 3 - state

React has two important stages, render stage and commit stage. In the render stage, react will deeply traverse the React fiber tree in order to find diffs. Different places are the places that need to be updated next. For changed components, the render function will be executed. After a reconciliation process is completed, the commit stage is reached. The commit stage will create and modify the real DOM node.

setState

/* The first parameter is of type function */
this.setState((state,props)=>{
    return { number:1 } 
})
/* The first parameter is object type */
this.setState({ number:1 },()=>{
    console.log(this.state.number) //Get the latest number
})

If the above setState is triggered once in an event, what are the main things done at the bottom of React?

  1. First, setState generates the current update priority (expirationTime)
  2. Next, React will pull down and child nodes from the root fiber of the fiber Root. In the reconciliation phase, it will compare the updated places, update and compare the expirationTime, find the updated components, merge the state, and then trigger the render function to get a new UI view layer to complete the render phase.
  3. In the commit phase, replace the real DOM and complete the update process.
  4. At this time, it is still in the commit phase. The callback function in setState will be executed, as shown above () = > {console. Log (this. State. Number)}. So far, the whole process of setState has been completed.

The update process is as follows:

setState principle

In Chapter 2 component, it is mentioned that the Updater object responsible for updating is bound during the initialization of class components. Calling the setState method is actually calling the enqueueSetState method on the Updater object at the bottom of React.

enqueueSetState(){
     /* Every time 'setState' is called, react will create an update and save it */
     const update = createUpdate(expirationTime, suspenseConfig);
     /* callback It can be understood as a setState callback function, the second parameter */
     callback && (update.callback = callback) 
     /* enqueueUpdate Pass the current update into the current fiber and the queue to be updated */
     enqueueUpdate(fiber, update); 
     /* Start scheduling updates */
     scheduleUpdateOnFiber(fiber, expirationTime);
}

Q: Is setState synchronous or asynchronous

From the bottom code of React, this problem involves the batch update concept of batchedEventUpdates and the conditions under which batch updates are broken.

function batchedEventUpdates(fn,a){
    /* Turn on batch update  */
   isBatchingEventUpdates = true;
  try {
    /* The event handling function executed here, such as triggering setState in a click event, will be executed in this function */
    return batchedEventUpdatesImpl(fn, a, b);
  } finally {
    /* try return inside will not affect finally execution  */
    /* Complete one event, batch update  */
    isBatchingEventUpdates = false;
  }
}

As can be seen from the above, before the execution of the React event, turn on the switch isBatchingEventUpdates=true to start the batch update of the event. When the event ends, turn on isBatchingEventUpdates = false; Turn off the switch, and then determine whether to batch update according to this switch in scheduleUpdateOnFiber.

Take the following example:

export default class index extends React.Component{
    state = { number:0 }
    handleClick= () => {
          this.setState({ number:this.state.number + 1 },()=>{   console.log( 'callback1', this.state.number)  })
          console.log(this.state.number)
          this.setState({ number:this.state.number + 1 },()=>{   console.log( 'callback2', this.state.number)  })
          console.log(this.state.number)
          this.setState({ number:this.state.number + 1 },()=>{   console.log( 'callback3', this.state.number)  })
          console.log(this.state.number)
    }
    render(){
        return <div>
            { this.state.number }
            <button onClick={ this.handleClick }  >number++</button>
        </div>
    }
} 

// Click Print: 0, 0, 0, callback1 1, callback2 1, callback3 1.

According to the above code, the whole React context execution stack will look like this:

Why is the batch update rule in asynchronous operation broken

setTimeout(()=>{
    this.setState({ number:this.state.number + 1 },()=>{   console.log( 'callback1', this.state.number)  })
    console.log(this.state.number)
    this.setState({ number:this.state.number + 1 },()=>{    console.log( 'callback2', this.state.number)  })
    console.log(this.state.number)
    this.setState({ number:this.state.number + 1 },()=>{   console.log( 'callback3', this.state.number)  })
    console.log(this.state.number)
})

// Print callback1, 1, callback2, 2, callback3, 3, 3

In the whole React context execution stack, it will become as follows:

How to continue to open the batch update mode in the above asynchronous environment

Batch update method unstable is provided in react dom_ Batch updates, you can manually batch update.

setTimeout(()=>{
    unstable_batchedUpdates(()=>{
        this.setState({ number:this.state.number + 1 })
        console.log(this.state.number)
        this.setState({ number:this.state.number + 1})
        console.log(this.state.number)
        this.setState({ number:this.state.number + 1 })
        console.log(this.state.number) 
    })
})

// Output 0, 0, 0, callback1 1, callback2 1, callback3 1

In practice, unstable_batchedUpdates can be used to merge multiple setstates or multiple usestates after Ajax data interaction.

Raise update priority

React DOM provides flushSync, which can put the update task in the callback function at a higher priority.

handerClick=()=>{
    setTimeout(()=>{
        this.setState({ number: 1  })
    })
    this.setState({ number: 2  })
    ReactDOM.flushSync(()=>{
        this.setState({ number: 3  })
    })
    this.setState({ number: 4  })
}
render(){
   console.log(this.state.number)
   return ...
}

//  Output 3 4 1

Supplementary notes to flushSync: under the condition of synchronization, flushSync will merge the previous setState | useState. It can be understood that if flushSync is found, the update will be performed first. If there are previously non updated setState ︱ usestates, they will be merged together. Therefore, as explained above, 2 and 3 are updated to 3 in batch, so 3 is printed first.

The update priority relationship of React at the same level is:

setState in flushSync > setState > setTimeout in normal execution context, setState in Promise.

useState

Basic Usage

 [ ①state , ②dispatch ] = useState(③initData)

There are also two cases for the parameters of dispatch:

  • In the first non functional case, a new value will be given to state for the next rendering;

  • The second is the case of a function. If the parameter of dispatch is a function, it can be called reducer here. The reducer parameter returns the latest state last time, and the return value is the new state.

// The disoatch parameter is a function
const [ number , setNumbsr ] = React.useState(0)
const handleClick=()=>{
   setNumber((state)=> state + 1)  // state - > 0 + 1 = 1
   setNumber(8)  // state - > 8
   setNumber((state)=> state + 1)  // state - > 8 + 1 = 9
}

Note: when calling the function dispatch that changes the state, the latest state value cannot be obtained in the context of this function execution. Because the function component update is the execution of the function, all variables inside the function are redeclared during one execution of the function. Therefore, the changed state will only be updated during the next execution of the function component.

useState principle

See later sections

The difference between setState and useState

  1. Same point
    From the bottom level, both setState and useState call the scheduleUpdateOnFiber method, and there are batch update rules in event driven cases.
  2. difference
  • The callback function of setState can obtain the latest state; However, in function components, the side effects caused by state changes can only be performed through useEffect.
  • In the underlying processing logic, setState is mainly merged with the old state, while useState is more inclined to reassign.

This article will learn from the "React advanced practice guide" in the Nuggets booklet

Tags: React

Posted on Sun, 28 Nov 2021 20:51:12 -0500 by rachae1