The ReactDOM. Render article mentioned the Render phase of the React update process. The name Render phase makes it easy for people to think that react will render the page at this stage, but it’s not. The Render phase is where React builds the workInProgress tree. This article gives a comprehensive overview of render’s work.

This article mentioned that performSyncWorkOnRoot is called for both the first render and subsequent page updates. This method calls renderRootSync, the entry to the Render phase

function renderRootSync(root, lanes) {
  var prevExecutionContext = executionContext;
  // Set the flags for the render phase
  executionContext |= RenderContext;
  var prevDispatcher = pushDispatcher();

  if(workInProgressRoot ! == root || workInProgressRootRenderLanes ! == lanes) { prepareFreshStack(root, lanes); startWorkOnPendingInteractions(root, lanes); }do {
    try {
      workLoopSync();
      break;
    } catch(thrownValue) { handleError(root, thrownValue); }}while (true);
  / /...
  return workInProgressRootExitStatus;
}
Copy the code

RenderRootSync has two important parts: prepareFreshStack and workLoopSync. Let’s first look at prepareFreshStack

function prepareFreshStack(root, lanes) {
 // ...
 // fiberRoot
 workInProgress = createWorkInProgress(root.current, null); 
 // ...
}
Copy the code

The global workInProgress variable is modified, and createWorkInProgress initializes a rootFiber of the workInProgress tree based on whether the workInProgress exists.

function createWorkInProgress(current, pendingProps) {
  var workInProgress = current.alternate;
  if (workInProgress === null) {
    // For the first render, create a new fiber object and initialize it
  } else {
    // Reset workInProgress for subsequent updates}}Copy the code

Now, when the preparation is complete, enter workLoopSync. WorkLoopSync is simply a loop

function workLoopSync() {
  while(workInProgress ! = =null) {
    // The global variable workInProgressperformUnitOfWork(workInProgress); }}Copy the code

PerformUnitOfWork is the processing of a single fiber node. This method will call beginWork and completeUnitOfWork to complete the processing of a fiber node. Let’s first talk about the process of traversing the Fiber tree.

The render phase adopts the depth-first traversal mode, beginWork processing is called when the node is traversed for the first time, completeUnitOfWork processing is called when the node is returned later, and the global variable workInProgress points to the node that is accessed.

Note: the global workInProgress variable is a pointer that changes as the fiber tree is traversed, and is not the root of the workInProgress tree

The execution sequence is as follows:

rootFiber beginWork App beginWork div1 beginWork span1 beginWork span1 completeUnitOfWork div2 beginWork span2 beginWork  span2 completeUnitOfWork div2 completeUnitOfWork div1 completeUnitOfWork App completeUnitOfWork rootFiber completeUnitOfWorkCopy the code

Now that you know the traversal process of the Render phase, let’s take a look at what beginWork and completeUnitOfWork have done

beginWork

First, beginWork will decide whether to reuse the existing structure according to whether the priority of the current fiber is enough. The specific logic is here

if(current ! = =null) {
  // The current fiber has been mounted, and now it is time to update
  var oldProps = current.memoizedProps;
  var newProps = workInProgress.pendingProps;

  if(oldProps ! == newProps || hasContextChanged() || ( workInProgress.type ! == current.type )) { didReceiveUpdate =true;
  } else if(! includesSomeLane(renderLanes, updateLanes)) { didReceiveUpdate =false; 
    switch (workInProgress.tag) {
     // Processing for different types of components
    }
    // Reuse existing structures
    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
  } else {
    if((current.flags & ForceUpdateForLegacySuspense) ! == NoFlags) { didReceiveUpdate =true;
    } else {
      didReceiveUpdate = false; }}}else {
  didReceiveUpdate = false;
}
Copy the code

The important thing is the switch statement

switch (workInProgress.tag) {
  case IndeterminateComponent: 
    // ...
  case LazyComponent: 
    // ...
  case FunctionComponent: 
    // ...
  case ClassComponent: 
    // ...
}
Copy the code

When an existing structure cannot be reused directly, different update logic is entered depending on the fiber type of the component. Future articles will focus on how to create updates for class and function components. Here’s a look at what beginWork does: For class and function components, beginWork calculates the updated state and executes the reconcileChildren method, known as the DIff phase. During the diff process, the corresponding workInProgress tree node is created according to the current tree, and an effect is placed on the fiber according to the render results before and after the update to indicate whether the fiber is updated, added or deleted. Finally, BeginWork returns workinProgress. child, which is the first child of the currently processed fiber node.

completeUnitOfWork

When the workInProgress pointer reaches the leaf of the fiber tree, the completeUnitOfWork method is executed. This method creates a DOM node corresponding to the fiber node, inserts it into its parent node, and collects the effect of the fiber. Create a linked effectList for the COMMIT phase.

This article describes the overall flow of the Render phase, followed by an introduction to how class components and function components are mounted and updated, i.e. the principles of setStates and hooks.