Master React component tree traversal skills

The version corresponding to this article reactis18.2.0

How is the following domstructure reacttraversed internally?

const  App = () => {
   return (
     < div > 
      < button > +1 </ button > 
      < A  count = {0} /> 
    </ div >
  );
};
const  A = ( props ) => {
   useEffect ( () => {
     console . log (props. count );
  }, [props.count ] );
   return  < div > {props.count} </ div > ;
};

reactInternal traversal core logic:

  1. function renderis called whencommitPassiveUnmountOnFiber
  2. commitPassiveUnmountOnFiberhandle different WorkTagand callrecursivelyTraversePassiveUnmountEffects
  3. recursivelyTraversePassiveUnmountEffectsDetermine whether to traverse the current child node according to whether the current Fiberchild node has passive effectuseEffect,, )useLayoutEffectFiber
    • If there are child nodes passive effect, traverse the child nodes first (depth first) until the final leaf node is found and exit the current loop.
    • Then enter the sibling node and start traversing the child nodes of the sibling node
      • Specifically which sibling node to start traversing from, reactselect the parent node of the leaf node that exits the loop, check whether there are any child nodes, and then traverse in a loop
    • Until finally all passive effectnodes with are found

Code simplification:

commitPassiveUnmountOnFiber (root. current );

function  commitPassiveUnmountOnFiber ( finishedWork ) {
   // Omitted to handle different WorkTag 
  recursivelyTraversePassiveUnmountEffects (finishedWork);
}

function  recursivelyTraversePassiveUnmountEffects ( parentFiber ) {
   // Other processing is omitted 
  if (parentFiber. subtreeFlags & PassiveMask ) {
     let child = parentFiber. child ;
     while (child !== null ) {
       commitPassiveUnmountOnFiber (child);child = 
      child.sibling ;
    }
  }
}

So domthe traversal logic for this paragraph is:

  1. First start from the root component FiberRootNodeand getcurrent
    • that is to say FiberRootNode.currentis div#rootthis is a fiberand its tagis3
  2. Since Appthere are subcomponents of passive effect, it will enter Appthe component, and its tagis0
  3. AppThe node in the component is <div><di >of tagis5
    • <div>There are two child elements below <button>,<A>
  4. The first thing to traverse <button>it tagis5
  5. <button>There is only one text node inside, nopassive effect
    • Therefore, reactit is no longer traversed (jumps out of the current traversal loop, that is, buttonthis article is no longer traversed)
  6. After jumping out of the loop, check the sibling buttonnodes <A>of<A>tag0
  7. Since <A>the node has no child nodes passive effect, it jumps out of the loop and ends the entire traversal.

Summarize

  1. Traverse starting from the following node
  2. Are there any subcomponents of the current component?passive effect
  3. Take depth first
  4. If domthere is a function component in the node, this domwill be traversed, otherwise it will not be traversed
  5. If there are no fiberchildren under the current , the entire linked list will not be traversed.fiberpassive effect
  6. These will not be traversed if there are currently fiberonlydomdom

In general, don’t traverse the components to see fiberif there are passive effect:

  • Yes, it will definitely be traversed
  • No, the following two situations will be traversed, and other situations will not be traversed.
    • is passive effectthe parent component of
    • and passive effectcomponents are siblings

passive effectRefers useEffect,useLayoutEffect

The traversal logic is shown in the figure below

Everything with a green tick in the picture will be traversed, and the red tick is the order of traversal.

Previous articles

  1. A deep dive into how React native events work
  2. React Lane Algorithm: Detailed explanation of 8 Lane operations in one article
  3. Analysis of React task scheduling mechanism: scheduleCallback implementation principle