preface

React updates the React update mechanism. React updates the React update mechanism. React updates the React update mechanism. May not be all correct, if there is a mistake or misunderstanding of the place, I hope you can put forward some of their own opinions in the comments section.

React update mechanism

Based on what I know about React’s mechanism so far, I’ve divided it into five stages

  • schedulSpace scheduling stage
  • reconcilePhase transformation
  • beginWorkDiff comparison phase
  • completeWorkMultiplexing node phase
  • commitUpdate the stage

Schedul phase

Schedul (Spatial Scheduler) has one at WiondwrequestIdleCallbacThe function,

requestIdleCallbac

Window. RequestIdleCallback () developers to the loop and low-level work performed on the background and key events without delay, such as animation and response. The functions are executed sequentially and then timeout has an execution order for sequential calls, which can be executed sequentially so that functions can be executed first and the execution order can be scrambled.

requestIdleCallbackIt takes two arguments, a callback function and a timeout,

 // Idle scheduling
    const workLoop = (deadline: any) = > {
        console.log(deadline, 'Parameters of spatial scheduling')
        // Is free
        let shouldYield = false;
        while(nextFiberReconcileWork && ! shouldYield) { nextFiberReconcileWork = performNextWork( nextFiberReconcileWork ) shouldYield = deadline.timeRemaining()  <1
        }

        // The conversion is complete and the commit phase is entered
        if(! nextFiberReconcileWork) { commitRoot() } requestIdleCallback(workLoop); } \Copy the code

I understand that the essence is that every callrequestIdleCallbackReturns a value of the remaining time, and the task that needs to be executed determines whether the remaining time is sufficient for the task to complete. If not, the task is paused. If sufficient, continue the mission.

That’s what React Fiber is all about. React performs updates recursively. This operation is uninterruptible. If it breaks, it will recurse again. Such a mechanism will cause page lag, which is not good for user experience

According to some articles, React’s underlying implementation is not actually implementedrequestIdleCallbackThis function, instead, implements itself from the bottom uprequestIdleCallbackA function of spatial scheduling

Schedul phaseWhat did you do?

Determine if there is enough time for the virtual DOM to convert to Fiber, and stop converting if not. If there is enough time, the conversion will continue until the end of the conversion

Reconcile phase

Convert Vdom into Fiber and connect each Fiber work unit through a certain structure to form a linked list

function performNextWork(fiber: any) {
        console.log(fiber,'fibelfibelfibel');
        reconcile(fiber);
        if (fiber.child) {
            return fiber.child;
        }
        let nextFiber = fiber;
        while (nextFiber) {
            if (nextFiber.sibling) {
                returnnextFiber.sibling; } nextFiber = nextFiber.return; }}Copy the code

In the code above, you can see the process of transformation, which I have divided into three processes

  • First find the child element of Fiber, the child element exists, return the child element as a fiber unit of work, and retry the schedule

  • If fibel sibling exists, return it as a Fiber unit of work and re-execute schedule

  • And finally return the parent of Fibel,

In this process, every time a Vdom is converted to a Fiber unit of work, it is re-executedschedule, determine whether there is enough time. If not, stop converting and render the page first. Wait for the next frame to continue the transformation until all the transformation is completed, perform the COMMIT phase, re-render the page in the next frame, if enough, continue the transformation, complete the transformation, execute the COMMIT, re-render the page.

reconcileIn the process, DOM nodes are also created based on Fiber. Finally, all the Fiber units of work are connected into a linked list, which is basically a Fiber tree.

beginWorkPhase, two trees are compared by diff algorithm.

Single-node DIFF comparison

  • If the nodes at the same level are different, discard the old Fiber node and create a new Fiber node
  • If the peer nodes are the same, then replace the props property of the Fiber node with the same keys
  • In accordance with the same comparison method, check until all Fiber nodes are compared

Multi-node DIff comparison

  • Check whether the nodes at the same level are the same. If not, discard oldFiber and create a new Fiber node
  • If the nodes are the same, check whether the Fiber node has moved its position. If so, mark it
  • If the nodes are the same and there is no moving position, just replace the props property of the Fiber node

beginWorkReact elements should have a key and React elements should not have an index.

React performs diff comparison. If two elements have the same keys, they are the same elements. You can directly replace the props property of the Dom and update it, without re-generating the Dom and saving performance. We use index as the unique identifier. If the array length is increased or decreased by 1, or an element is moved, the corresponding index will also change. In the React comparison case, the previous element will be deleted and the same element will be created again

The React Diff phase compares labels first if the key is not set. The React diff phase compares labels first if the key is set to index. Here's how to learn React again. Pay attention to this problem

completeWorkphase

This is the subsidiary stage of DIFF, and an upward comparison will be made to reuse oldFiber as much as possible to improve performance. Meanwhile, the Fiber tree that has been compared will be added to the update queue, and rendering will be completed in the COMMIT stage

commitUpdate the DOM

// commitRoot
    function commitRoot() { commitWork(wipRoot? .child); wipRoot =null
    }

    // commitWork
    function commitWork(fiber: any) {
        if(! fiber) {return
        }
    
        let domParentFiber = fiber.return
        while(! domParentFiber.dom) { domParentFiber = domParentFiber.return }const domParent = domParentFiber.dom
    
        if (
            fiber.effectTag === "PLACEMENT"&& fiber.dom ! =null
        ) {
            domParent.appendChild(fiber.dom)
        } 
        commitWork(fiber.child)
        commitWork(fiber.sibling)
    }
Copy the code

commitThe phase is rendered according to the structure of the Fiber tree child, Sibling, return, and inserted into the DOM because in thereconcileThe DOM phase is already created, and the diff phase knows which operations to delete, add, and move, so the COMMIT phase is quick

Render view, React update done

The React update mechanism is a bit of a beginner's game. This is just my own understanding of the React update mechanism. If you have any mistakes or better insights, please feel free to comment below.