react source code analysis - the Mutation stage in the commit process and the removal of DOM nodes

catalogue

Entry of deletion operation and related sequence

Internal process of delete operation

Talk about several specific methods in the Mutation stage of commit

summary

2021SC@SDUSC

Entry of deletion operation and related sequence

The DOM node operation is formally completed in commitMutationEffects, and the DOM node operation is completed in commitMutationEffects_ In begin, initialize nexteffect to root, and then cycle through deleting its child nodes. When the child nodes are null, call commitMutationEffects_complete, in this method, first update and insert the corresponding Fiber node, and then check whether there is a brother node. If there is a brother node, assign the brother node to nexteffect and return to continue by ommitMutationEffects_begin (find the node that can be deleted). If there is no sibling node, assign nexteffect as the parent node and continue in commitMutationEffects_ Process in complete. This ensures that the insert or update operation can be performed after the delete operation is completed. (the deletion operation is performed first to reduce confusion and improve the correctness of building and updating DOM trees).

function commitMutationEffects_begin(root: FiberRoot) {
  while (nextEffect !== null) {
    const fiber = nextEffect;

    // TODO: Should wrap this in flags check, too, as optimization
    const deletions = fiber.deletions;
    if (deletions !== null) {
      for (let i = 0; i < deletions.length; i++) {
        const childToDelete = deletions[i];
        try {
          commitDeletion(root, childToDelete, fiber);
        } catch (error) {
          reportUncaughtErrorInDEV(error);
          captureCommitPhaseError(childToDelete, fiber, error);
        }
      }
    }

    const child = fiber.child;
    if ((fiber.subtreeFlags & MutationMask) !== NoFlags && child !== null) {
      ensureCorrectReturnPointer(child, fiber);
      nextEffect = child;
    } else {
      commitMutationEffects_complete(root);
    }
  }
}

function commitMutationEffects_complete(root: FiberRoot) {
  while (nextEffect !== null) {
    const fiber = nextEffect;
    setCurrentDebugFiberInDEV(fiber);
    try {
      commitMutationEffectsOnFiber(fiber, root);
    } catch (error) {
      reportUncaughtErrorInDEV(error);
      captureCommitPhaseError(fiber, fiber.return, error);
    }
    resetCurrentDebugFiberInDEV();

    const sibling = fiber.sibling;
    if (sibling !== null) {
      ensureCorrectReturnPointer(sibling, fiber.return);
      nextEffect = sibling;
      return;
    }

    nextEffect = fiber.return;
  }
}

Internal process of delete operation

Now you can formally delete. First, you need to find the parent node of the DOM node in the target node (there are usually more Fiber tree nodes than DOM tree). If the target node is a DOM node, you can delete the child node by using the parent node after traversing and eliminating its Fiber child node (calling commitNestedUnmounts). If the target node is not a DOM node, you need to traverse its child nodes (commitUnmount is called to eliminate its own Fiber node) until the DOM node is found. After finding it, eliminate its child nodes and delete the DOM node.

The types of deleted DOM nodes may include HostComponent, HostText, DehydratedFragment, and HostPortal. Most use commitUnmount to delete their child nodes. You can see the unloading process of many components, such as the clearing function of useEffect in function components (using the return keyword), such as the life cycle function componentWillUnmount in class components, and the host component (derived label node) deleting its own ref.

Talk about several specific methods in the Mutation stage of commit

The first is commitresetttextcontent, which is used to empty the text content of the node. This method calls   resetTextContent method, and resetTextContent will call setTextContent method. In this method, it will check whether the text text exists. If it exists and there is only one child node of the node and it is a text node, set the nodeValue of the text node to text. If the text node does not exist, directly set the textContent of the node to text, The text node we passed in is' ', which is tested here

Therefore, textContent will be set to the specified text in this method.

Let's take a look at the commitDetachRef method. The source code is given here

function commitDetachRef(current: Fiber) {
  const currentRef = current.ref;
  if (currentRef !== null) {
    if (typeof currentRef === 'function') {
      if (
        enableProfilerTimer &&
        enableProfilerCommitHooks &&
        current.mode & ProfileMode
      ) {
        try {
          startLayoutEffectTimer();
          currentRef(null);
        } finally {
          recordLayoutEffectDuration(current);
        }
      } else {
        currentRef(null);
      }
    } else {
      currentRef.current = null;
    }
  }
}

If the node has a ref that needs to be cleared, execute this method. If ref is a function type, you can check whether the timer can be started and count the time when it can be started. I will describe the specific functions of various expiration and update times in react later. If it is not a function type. It will directly point ref to clear.

summary

This paper introduces the execution sequence and process of deleting, inserting and updating nodes in the commit operation tree, with emphasis on the internal process in the deletion process.

 

Tags: Front-end React

Posted on Sun, 28 Nov 2021 11:17:33 -0500 by yacaph