An overview of

In this chapter we will uncover the mystery of Render and reveal how the React Render phase builds the Fiber tree.

First, let’s look at render’s call stack:

Render phase began in performSyncWorkOnRoot (update) or performConcurrentWorkOnRoot asynchronous update () method.

The two methods end up calling workLoopSync or workLoopConcurrent as follows:

// Update synchronously
function workLoopSync() {
  while(workInProgress ! = =null) { performUnitOfWork(workInProgress); }}// Update asynchronously
function workLoopConcurrent() {
  while(workInProgress ! = =null&&! shouldYield()) { performUnitOfWork(workInProgress); }}Copy the code

From the code, we can see that the workInProgress is determined during the update process, while asynchronous updates call the shouldYield() function to determine the workInProgress (Concurrent mode main logic code).

  • workInProgress: represents the fiber tree being built in memory, inperformUnitOfWorkCreates a child node fiber and assigns it toworkInProgress(Depth-first traversal)
  • ShouldYield: represents the function ofshouldYieldToHost
shouldYieldToHost = function() {
      const currentTime = getCurrentTime();
      if (currentTime >= deadline) {
        if (needsPaint || scheduling.isInputPending()) {
          return true;
        }
        return currentTime >= maxYieldInterval;
      } else {
        return false; }};Copy the code

The shouldYield() function determines curentTime>=deadline and, if true, termines the current update, swapping control to the browser.

This chapter focuses on synchronous processes and introduces asynchrony later in Concurrent

Here’s a quick look at the performUnitOfWork function:

function performUnitOfWork(unitOfWork: Fiber) :void {
  const current = unitOfWork.alternate;
  setCurrentDebugFiberInDEV(unitOfWork);

  let next;
  if(enableProfilerTimer && (unitOfWork.mode & ProfileMode) ! == NoMode) {// Start rendering time
    startProfilerTimer(unitOfWork);
    / / build workInProgress
    next = beginWork(current, unitOfWork, subtreeRenderLanes);
    // The rendering time
    stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
  } else {
    next = beginWork(current, unitOfWork, subtreeRenderLanes);
  }

  resetCurrentDebugFiberInDEV();
  // Props props for the next update
  unitOfWork.memoizedProps = unitOfWork.pendingProps;
  if (next === null) {
    // If this doesn't spawn new work, complete the current work.
    // if the current node has no child nodes, the current node is directly complate
    // Complete the creation of the effectList
    completeUnitOfWork(unitOfWork);
  } else {
    workInProgress = next;
  }

  ReactCurrentOwner.current = null;
}
Copy the code

The main function of performUnitOfWork is to call beginWork() and completeUnitOfWork(). BeginWork () is the capture phase, in which the depth-first method is adopted to traverse nodes, and the creation of Fiber tree and the DIff algorithm are completed. CompleteUnitOfWork () is the bubble phase, which completes (part of) the calls of the life cycle, forming an EffectList, etc.

Capture phase

In the capture phase, each node is traversed depth-first, and beginWork() is called during the traversal. In this method, the construction of the fiber tree and the Diff algorithm are completed (diff algorithm will be explained in detail later). There are two ways to create a fiber tree:

  • If fiber.alternate == null, fiber is created from JSX data, indicating that the current node has no rendered nodes corresponding to it.
  • If the fiber alternate! = null, fiber multiplexes fiber.alternate and is reassigned according to JSX to indicate that the current node has a rendering node corresponding to it.

As the capture phase recurses to the leaf, it bubbles up, so let’s look at the bubble phase.

Bubbling phase

The entry function in the bubble phase is completeUnitOfWork(), in which part of the life cycle call is completed and effectList is created to determine whether there are sibling nodes in the current fiber. If so, the sibling node enters the capture phase; if not, the parent node enters the bubble phase.

So what exactly is the process of capturing and bubbling? Here’s an example:

function App() {
    return (
      <div>
        <p>{this.state.count}</p>
        <button >click me</button>
      </div>
    )
}
ReactDOM.render(
  <App />.document.getElementById('root'));Copy the code

  • Step 1: FiberRoot Beignwork
  • Step 2: App Fiber beignWork
  • Step 3: Div Fiber beignWork
  • Step 4: P Fiber beignWork
  • Step 5: Because the text child node is behind the P node, React will be optimized and directly carry out the completeUnitOfWork phase. After completion, set the workInProgress to Button fiber
  • Step 6: Button Fiber beignWork
  • Step 7: Same as step 5 optimization of p node, Button will be directly completeUnitOfWork stage
  • Step 8: Div completeUnitOfWork
  • Step 9: App completeUnitOfWork
  • Step 10: FiberRoot completeUnitOfWork

conclusion

This chapter has a general understanding of the main functions of the Render phase, and the next chapter will begin the detailed explanation of the Render process

This article is partially based on React technology disclosures