Series of articles (updated)

  • React render phase 1: React Render phase 2: React Render phase 2: React Render phase 2: React Render
  • React render phase (2) : beginWork
  • React render phase (3) : completeUnitOfWork

React V17.0.0-alpha this series of articles discusses the source code for React V17.0.0-alpha

React workflow

React workflow is divided into render and COMMIT phases:

  • The render phase converts JSX into ReactElement (more specifically, JSX is converted by Babel into reac.createElement () wrapped code during code compilation, The Fiber tree is created in the Render phase by generating the corresponding ReactElement object. React uses the idea of “dual caching”, so two Fiber trees are maintained at the same time. One is current, which corresponds to the browser’s currently rendered DOM tree, and the other is workInProgress. Is a working copy of the Reconciler created at initialization or after the component status is updated.
  • The Commit phase refers to rendering the workInProgress onto the page. This process does not involve a full update, but rather determines what to do on a DOM node based on the effectTags used to create the workInProgress. For example, update text, delete nodes, etc., to restore workInProgress in the DOM as little as possible. WorkInProgress will be marked as Current after commit.

Render stage entry

Render phase began in performSyncWorkOnRoot or performConcurrentWorkOnRoot method invocation, the difference of these two methods is a synchronous, and the other is asynchronous (concurrent).

These two methods call the following two methods, workLoopSync and workLoopConcurrent, respectively:

function workLoopSync() {
  // Already timed out, so perform work without checking if we need to yield.
  while(workInProgress ! = =null) { performUnitOfWork(workInProgress); }}function workLoopConcurrent() {
  // Perform work until Scheduler asks us to yield
  while(workInProgress ! = =null&&! shouldYield()) { performUnitOfWork(workInProgress); }}Copy the code

The difference between the two methods is whether shouldYield() is called to determine if the current browser frame has any free time. For concurrent mode, if there is no free time, the current loop will exit; You can see that both methods end up calling FormUnitofWork.

Through the while loop in the method, Fiber Reconciler will create the entire workInProgress Fiber Tree through a strategy of “deep traversal.”

performUnitOfWork

function performUnitOfWork(unitOfWork: Fiber) :void {
  const current = unitOfWork.alternate; // The corresponding Fiber node in the current tree may be null
  / /... omit

  let next; // Hold the result returned by beginWork()
  if(enableProfilerTimer && (unitOfWork.mode & ProfileMode) ! == NoMode) {/ /... omit
    next = beginWork(current, unitOfWork, subtreeRenderLanes);
    / /... omit
  } else {
    next = beginWork(current, unitOfWork, subtreeRenderLanes);
  }

  / /... omit
  unitOfWork.memoizedProps = unitOfWork.pendingProps;
  if (next === null) { // beginWork returns null, indicating that there are no subfiber nodes of the current node
    completeUnitOfWork(unitOfWork);
  } else {
    workInProgress = next; / / the next workLoopSync/workLoopConcurrent main loop of the while loop for Fiber node
  }

  / /... omit
}
Copy the code

Since the Fiber Reconciler is reconstructed from the Stack Reconciler, it actually simulates the implementation of “recursion,” which is also actually a process similar to “depth-first traversal.” Formunitofwork is a specific method to control the “recursive” process, which mainly includes:

  1. “Pass” stage — beginWork
  2. “Return” stage — completeUnitOfWork

End condition for recursion

In combination with the workLoopSync and workLoopConcurrent methods of performUnitOfWork, the recursive traversal is complete as soon as the Fiber pointer to the workInProgress node is set to null.

function workLoopSync() {
  // Already timed out, so perform work without checking if we need to yield.
  while(workInProgress ! = =null) { performUnitOfWork(workInProgress); }}Copy the code

The “pass” stage of render — beginWork

In the “pass” phase, the beginWork method is called to generate the subfiber node, and the workInProgress points to the new Fiber node as the unitOfWork for the next loop. But depending on the situation, the beginWork might return NULL, which is the termination condition for recursion.

The “attribution” stage of render — completeUnitOfWork

Once the beginWork returns NULL, which satisfies the termination condition of the recursion, the “return” phase of the loop — completeUnitOfWork — is entered

In the “return” stage, the completeWork method is mainly called to gather up all the data from the descendant Fiber nodes (also known as sub-fiber node trees) into the unitOfWork

Then, it determines whether there are siblings, and if so, points the workInProgress pointer to the sibling as the unitOfWork for the next loop; Otherwise it loops back to the parent (which also executes completeWork) until it finds a sibling to enter the next loop (FormUnitofWork), Or the parent node is null(at which point the workInProgress pointer will point to NULL).

Note: The workInProgress pointer variable is in the parent scope of the completeUnitOfWork, so the completeUnitOfWork method does not need a return to assign the workInProgress pointer.

Recursive complete

If the workInProgress pointer points to null in the completeUnitOfWork, the entire workInProgress tree has been traversed.

At this point, all the work of render stage is completed. In the performSyncWorkOnRoot function, fiberRootNode is passed to the commitRoot method, starting the commit phase workflow.

Give an example of recursion

function App() {
    return (
        <p>
            <span>array</span>
            <span>huang</span>
        </p>
    )
}

ReactDom.render(<App />.document.getElementById('#root'));
Copy the code

1. rootFiber beginWork 2. App Fiber beginWork 3. p Fiber beginWork 4. span Fiber beginWork 5. span Fiber completeWork // Notice that this is going straight to the "return" stage of the SPAN, Span Fiber beginWork 7. Span Fiber completeWork 8. P Fiber completeWork 9 completeWork 10. rootFiber completeWorkCopy the code