preface

When it comes to react, we must mention the coordination process of Fiber Tree, diff algorithm comparison, and update side effects. In the previous Ramble on React Series (I) : Preliminary Study of react, we just made a brief overview of the work process of React, without giving a detailed description of its core content. Spend a lot of space to introduce some basic knowledge, mainly to pave the way for this article, in order to help you better understand this article.

This paper will introduce the whole coordination process of Fiber Tree, diff algorithm, and side effects treatment in detail based on the talk about react series 1: Preliminary work process of React. The article is long in length and uses a large number of pictures to help you understand. It may take some time for you to read it. I hope you can have some harvest after reading it.

The table of contents for the article is as follows:

  • Coordinate to Reconcile
  • WorkInProgress Nodes in the Fiber tree
  • The diff algorithm
    • How to determine if a Current Fiber node is clonable
    • The core idea of diff algorithm
    • Why use keys when child elements are lists
    • Diff algorithm comparison process
  • How to determine if a workInProgress Fiber node has changed
    • pendingProps & memoizedProps
    • Fiber node of the tag
    • A policy to determine whether a node has changed
    • The processing mode after the node changes
  • Side-effect-effect
    • The type of effect
    • Effect of collection
    • Effect of processing
  • Write in the last
  • The resources
  • portal

Coordinate to Reconcile

The React update is an update to the Fiber Tree structure. In more technical terms, the update of the Fiber Tree structure is actually the coordination of fiber Tree — Reconcile. Reconcile, Reconcile, Reconcile To coordinate the Fiber Tree, you need to adjust the structure of the Fiber Tree to be consistent with the updated JSX template structure and DOM Tree.

Fiber Tree There are two trees: Current Fiber Tree and workInProgress Fiber Tree. The entire coordination process takes place in the workInProgress Fiber Tree.

When coordinating, fiber Tree does three things:

  • Generate fiber node for Fiber tree;

  • Find the changed Fiber node, update the Fiber node, and mark side-effect;

  • Collect fiber nodes with effect;

So how does this process work?

Before answering this question, let’s review a familiar knowledge point in our student days – middle order traversal of binary tree.

The coordination process of fiber tree can also be understood by the middle order traversal of binary tree:

Is the above code almost identical to the middle order traversal of a binary tree? If the code doesn’t make sense, let’s break down the process and use a diagram to illustrate it:

Combined with the above diagram, it should be relatively easy to understand.

In fact, the source code implementation of the Fiber Tree coordination process in React is not like this, but the idea and process are similar. If you are interested in watching the React source code, you can use the binary tree’s middle order traversal as a guide.

WorkInProgress Nodes in the Fiber tree

WorkInProgress Fiber Tree As a new tree, there are three ways to generate fiber nodes:

  • Clone (shallow copy) Current Fiber node;
  • Create a New Fiber node
  • Direct multiplexing of Current Fiber node;

Different creation methods result in different DOM operations:

  • If the current fiber node is cloned (shallow copy), it means that the original DOM node can be reused directly, just need to update the dom node attributes, or move the DOM node.
  • If you want to create a fiber node, add a DOM node.
  • If the current fiber node is directly multiplexed, the corresponding DOM node does not need to do any processing at all.

To summarize, there are two kinds, either reuse, or new (cloning is also new). So when should you reuse and when should you create?

Before we answer that question, let’s look at a very simple example: demo

Click the Modify button to call setName, setVisible. Component’s name changes and needs to be updated. Component2 doesn’t need to update its name because it doesn’t match compare.

In this example, the children of Component need to be recreated, while the children of Component2 will all reuse the Current Fiber node.

The reason why current Fiber node is reused is because Component2 does not need to be updated, the corresponding function method is not executed, and the new React Element is not returned.

The same applies to class components. When a class component doesn’t need to be updated (shouldComponentUpdate returns false), the Render method doesn’t need to be executed, it doesn’t return a new React Element, and the child nodes reuse the Current Fiber node directly.

Therefore, in a React update, as long as the component and its child render methods (class component render, function component method) are not fired and the new React element is not returned, the child node can directly reuse the Current Fiber node.

Instead, as soon as the component’s render method is triggered to return a new React Element, fiber nodes need to be created for the child nodes based on the new React Element.

ShouldComponentUpdate and React.memo can be used to prevent unnecessary components from rerendering, and current Fiber node can be reused directly. Accelerate the coordination of workInProgress Fiber Tree to achieve the purpose of optimization.

Except for the reuse of current Fiber node, other nodes of the workInProgress Fiber Tree are all newly built, and the process of newly built nodes is related to the diff algorithm we often mention.

The diff algorithm

In fiber Tree coordination, if the render method of the component node is triggered to return a new React Element, the child nodes of the component node need to be newly created.

You can create a node in either of the following ways:

  • If a matching node can be found in the current Fiber tree, create a new node by cloning (shallow copy) the current Fiber node.

  • Conversely, if a matching node cannot be found in the Current Fiber Tree, a new node needs to be created.

This is actually pretty straightforward. When creating a node, if the difference between the node and the original node is not large, you can create a new node according to the original node, and then simply modify it. If you find that the node you want to create is too different from the original node, you have to create a new node.

The diff algorithm we often talk about is used to determine whether a Fiber node needs to be created by cloning the Current Fiber node.

How to determine if a Current Fiber node is clonable

One thing we need to be clear about is that the people who are doing the diff comparison, The React Element for workInProgress Fiber Tree and the Fiber node for Current Fiber Tree The React Element is compared with the Current Fiber node to determine how to create a fiber node for the workInProgress Fiber Tree.

Key is pretty straightforward. It is the key attribute on an element in a JSX template, as in:

<Component key="A" name="xxxx" /> // key="A" <div>... </div> // key=undefined <button> </button> // key=undefined < react. Fragment>... </React.Fragment> // key=undefinedCopy the code

When a JSX template is converted to a React Element, the element’s key property is used as the React Element’s key property. Similarly, when a React Element is converted to a Fiber node, the React Element’s key property is used as a Fiber node’s key property.

Type is a little more complicated to understand. Elements in JSX, in general, can be divided into three types:

  • Components, such as “< Component />”;
  • Dom nodes such as “< div >…
    “, “< button >…
    “;
  • React provides elements such as “< react.Fragment />”, “< react.Suspense>… “;

Different element types result in different types, as follows:

<Component key="A" name=" XXXX "/> // type = Component is A function <div>... </div> // key=undefined // type=" div", which is a string </button> button </button> // type="button", which is a string </ react. Fragment>... </ react. Fragment> // type = react. Fragment, which is a number (defined internally in React);Copy the code

After a JSX template is converted to react Element, the React Element’s Type attribute is assigned a different value depending on the type of the JSX element. It may be a component function, a DOM tag string, or a number. When a React Element is converted to a Fiber node, the React Element’s Type attribute will also be used as the Fiber node’s Type attribute.

To sum up, the logic of copying current Fiber node can be summarized as follows:

  • ReactElement. Key === currentFiberNode. Key && reactElement. Type === currentFiberNode.

  • reactElement.key ! Currentfibernode. key, Current Fiber node cannot be cloned;

  • reactElement.key === currentFiberNode.key && reactElement.type ! Currentfibernode. type, Current Fiber node cannot be cloned;

The core idea of diff algorithm

Core idea of DIFF algorithm:

  • Direct child nodes of matched parent nodes are compared, but not across parent nodes.

    That is, the child nodes of the cloned workInProgress Fiber node and the corresponding Current Fiber node are compared.

    Note that direct children of matched parent nodes are compared, not nodes of the same level. Many articles compare nodes at the same level, which is not accurate enough.

  • Compare the key and type to determine whether to clone the Current Fiber node. Clone the Current Fiber node as a new node only if the key and type are equal; otherwise, create a new node.

    Key value and node type – type. The key has a higher priority. If the key values are different, the nodes cannot be cloned.

  • All children of the same parent node must have unique keys.

Why use keys when child elements are lists

We believe that in daily development, also encountered the following warning information:

React prints this warning if the child element is a list and there is no key defined for each child element.

So what’s the point of using key?

The biggest significance of using key is that when the position of the list element changes, only dom movement is required, and unnecessary additions and deletions are not required.

Let’s look at an example: list:

In our example, we defined two components Componet1 and Component2. The list element in Component1 defines a key, and the list element in Component2 does not define a key. Click on the title element to reorder the list elements.

To listen for moves, additions, and deletions of DOM elements, we override createElement, appendChild, insertBefore, and removeChild methods.

When we click on the title for Component1, the element position changes, and the console just prints insertBefore, indicating that the DOM element has only been moved.

When we click on the header for Component2, the element position changes, and the console prints createElement, removeChild, insertBefore, indicating that the DOM element has been created and deleted.

Thus, if the child element to be rendered is a list, it can be optimized to some extent by giving the child a key.

Diff algorithm comparison process

React Element vs. Current Fiber node

  • Single React Element VS current Fiber node list;

  • React Element list VS Current Fiber node list;

In the current Fiber tree, sibling nodes are connected through the Sibling pointer, which is a linked list, so it will be used as a list in comparison. If there is only one Fiber node, sibling points to null and there is only one element in the list.

single react element VS current fiber node list

Single React Element and current Fiber node list Compare the key and node type – type of each Current Fiber node and react Element. React Element and Current Fiber node match only if the key and type are equal.

If there is no key value, the key is undefined, undefined === undefined, and the key value is equal. In addition, there are more detailed comparison details in kasong’s single node diff article, we can go to see, further understanding.

There are two final comparison results:

  • A node in the Current Fiber node list matches the React Element

    Clone current Fiber node as workInProgress Fiber node corresponding to react Element WorkInProgress Fiber node Alternate pointer to current Fiber node.

    All unmatched nodes in the current fiber node list are marked Deletion.

  • There are no nodes in the Current Fiber node list that match the React Element

    If there is no current Fiber node to match, create a new fiber node for the React Element as workInProgress Fiber node. The alternate pointer for the workInProgress Fiber node points to null.

    All nodes in the current fiber node column are marked Deletion.

Here is:

react element VS current fiber node list

The React Element List is slightly more complicated than the Current Fiber Node list.

When there is only one React Element, creating a workInProgress Fiber node is only a matter of whether to clone the current fiber node (shallow copy) or create a new fiber node from scratch. However, if there are multiple React Elements, we also need to consider whether the wokrInProgress Fiber node has been moved relative to the cloned (shallow copy) Current Fiber node.

So how do you judge oneClone (shallow copy) workInProgress from the Current Fiber node Whether the fiber node has been moved?

The answer is: index by list.

The Current Fiber Node List and workInProgress Fiber Node List, as a list, have corresponding subscripts oldIndex and newIndex. When workInProgress Fiber node and Current Fiber node establish clone (shallow copy) matching relationship, newIndex and oldIndex are also corresponding. In the legend above, the newIndex of workInProgress Fiber node-c is 0, and the oldIndex of the corresponding Current Fiber Node-c is 2.

WorkInProgress Fiber nodes are generated in sequence, using a pointer called lastPlacedIndex to locate current Fiber nodes that have not moved. By comparing lastPlasedIndex with oldIndex, we can know whether the node has moved:

  • If lastPlacedIndex > oldIndex, the node with the smaller oldIndex has moved behind the node with the larger oldIndex.

  • If lastPlacedIndex < oldIndex, the node has not been moved, and lastPlacedIndex needs to be updated.

Let’s combine the above legend to illustrate the node movement process:

  1. WorkInProgress Fiber node -c Matches current Fiber node -c, where newIndex is 0 and oldIndex is 2. Node C does not move, lastPlacedIndex is 2;

  2. WorkInProgress Fiber node -b matches current fiber node -b, newIndex = 1, oldIndex = 1, oldIndex < lastPlacedIndex, Node B moves behind node C;

  3. WorkInProgress Fiber node -a matches current Fiber node -a, newIndex = 2, oldIndex = 0, oldIndex < lastPlacedIndex, Node A has moved, behind node C;

  4. WorkInProgress Fiber node -d matches current fiber node -d, newIndex = 3, oldIndex = 3, oldIndex > lastPlacedIndex, Object D is not moved and the lastPlacedIndex is updated to 3;

React Element List and Current Fiber Node List compare react Element List with Current Fiber node list

During the comparison, react iterates through the React Element list in order, looking for matching nodes from the Current Fiber Node list. In comparison, the condition of unequal key values is used as the watershed, and the whole process is divided into two stages:

  • In the first phase, the key values are not unequal.

    At this point, the React Element List and the Current Fiber Node List are traversed side by side. Type same, match, clone current Fiber node; If the type is different or does not match, create a fiber node and mark Deletion on the current fiber node.

    If the key values are different, phase 1 ends and phase 2 enters.

  • In the second phase, the key value does not match.

    At this point, a Map is generated according to the remaining current fiber node list, where key is the key of the current fiber node (if there is no key, use index) and value is the current fiber node. Continue traversing the remaining React Elements to find matching Current Fiber nodes from the Map.

    If it can be found, clone the Current Fiber node, otherwise create a new Fiber node. All unmatched nodes in the Map are marked Deletion.

The whole process of comparison is described in more detail in Kasong’s multi-node diff, which can be combined with the big guy’s article to understand.

You may be confused at 😳, so let’s use an auxiliary example to illustrate the whole process and help you understand the above two stages.

First, let’s look at examples and results:

In the figure above, we can clearly see which of the workInProgress Fiber nodes are new, which are clones (shallow copies) from the Current Fiber node, which are moved, and which need to be deleted.

Next, let’s analyze the process in between:

In this way, after diff algorithm comparison, the nodes to be created in the workInProgress Fiber Tree are established. Next we need to determine whether the new node has changed. If the node changes, you need to update the node and collect the effects caused by the update.

How do I determine whether a newly created node has changed

By learning the diff algorithm in the previous section, we know that there are two ways to create a workInProgress Fiber node: clone (shallow copy) current Fiber node and recreate a Fiber node

If a workInProgress Fiber node is newly built, it is safe to say that the fiber node has been changed from scratch.

If a workInProgress Fiber node is cloned (shallow copy) from a current Fiber node, then we need to determine whether the workInProgress Fiber node has changed.

Before we go into judgment strategies, we need to prepare a few things: pendingProps & memoizedProps and Fiber Node tags.

pendingProps & memoizedProps

JSX -> React Element -> Fiber nodes react element -> Fiber nodes react element -> Fiber nodes react element -> Fiber nodes react element -> Fiber nodes react element During this process, all properties defined on the JSX element (except for the key) are collected into the React Element’s props property.

As follows:

// jsx <Component name="xxx" age="18" address="xxxx" onClick={() => {... }} /> // react element { type: Component, key: undefined, props: { name: 'xxx', age: "18", address: "xxxx", onClick: () = > {... }}}Copy the code

When the React Element is converted to the workInProgress Fiber node, the React Element’s props property is assigned to the pendingProps of the workInProgress Fiber node. When the workInProgress Fiber node is finished processing, the pendingProps property value is assigned to memoizedProps. Because workInProgress fiber node will be updated as the next current fiber node, so we can pass currentFiberNode. MemoizedProps to get the last update JSX element attribute values.

/ / workInProgress fiber node workInProgressFiberNode. When just created pendingProps: {name: 'XXX', the age: "18", address: "xxxx", onClick: () => {... }}; . / / workInProgress fiber node through creating workInProgressFiberNode memoizedProps: {name: 'XXX', the age: "18", address: "xxxx", onClick: () => {... }}; . / / fiber node - the next update currentFiberNode memoizedProps = {name: 'XXX', the age: "18," address: "XXXX", onClick: () = > {... }};Copy the code

PendingProps is the props of the workInProgress Fiber node generated by this update, while memoizedProps is the props of the current Fiber node before the update. By comparing the pendingProps and memoizedProps, you can see if the workInProgress Fiber Node has changed.

Fiber node of the tag

In the diff algorithm section, we learned that each Fiber node has its own type-type: component type, DOM node type, react special element type.

React tags fiber nodes differently depending on type:

  • Component type – if a ClassComponent, the tag is ClassComponent; If it is a FunctionComponent, the tag is FunctionComponent;
  • Dom node type – tag is HostComponent.
  • React special element types – Fragment, SuspenseComponent, etc.

Different tags require different processing when the workInProgress Fiber node is determined to change.

A policy to determine whether a node has changed

For all types of nodes, check whether the workInProgress Fiber node pendingProps is equal to the Current Fiber Node memoizedProps. To determine whether the workInProgress Fiber node has changed. If workInProgressFiberNode pendingProps! . = = currentFiberNode memoizedProps, then explain workInProgress fiber node has changed, you need to update.

In general, as long as the workInProgress Fiber node is created from the new React Element, The workInProgress Fiber Node pendingProps must be different from the Current Fiber Node memoizedProps.

Each time a React Element is created, the props is a new object, resulting in a new object for the pendingProps of the workInProgress Fiber node. The memoizedProps of the Current Fiber node are the props of the React Element generated during the last update. The two objects are completely different.

This explains why when a child node is a component, the component still needs to trigger the Render method, even though the properties in props are the same and the values of the properties are the same. This is because the fiber node corresponding to the subcomponent is newly created, and although the props looks the same, it is actually a new object. When the props changes and the node is updated, the render method is triggered.

Also, if the node is a component type, you need to see if the state of the component has changed. The node needs to be updated whenever either the props or state of the component changes.

In summary, the strategy for judging whether the node changes is as follows:

  • Whenever a node is recreated rather than cloned from a Current Fiber node, the node is 100% changed and needs to be updated;

  • The node is cloned from the Current fiber node. If the props are changed, the node needs to be updated.

  • The node is cloned from the current Fiber node and is a component type. You can also compare whether the state has changed. If the state has changed, the node needs to be updated.

The processing mode after the node changes

First of all, the workInProgress Fiber node is created in different ways, and the processing logic is different when the changes need to be updated:

  • The node is recreated instead of cloned from the Current Fiber node, which requires mount operation.

  • The node is created by cloning the Current Fiber node, and the update operation is required.

In addition, the processing logic of workInProgress Fiber node updates is different depending on the tag. In daily development, the types we deal with most are component types and DOM types, so this article will focus on the processing logic when these two types of nodes are updated, and we will introduce the other types of nodes separately in the future.

Component Type Fiber node

Component types can be divided into classcomponent-classComponent and functioncomponent-functionComponent.

The mount and update operations for these two types of nodes are as follows:

  • ClassComponent – ClassComponent

  • FunctionComponent – FunctionComponent

Fiber node of dom node type

Side-effect-effect

In the coordination process of workInProgress Fiber Tree, side-effect will be generated as long as any node changes and is updated. Side effects refer to the addition, removal, deletion, attribute update of DOM nodes, the execution of componentDidMount, componentDidUpdate and other life cycle methods.

After fiber Tree coordination is complete, the fiber Tree enters the COMMIT phase. In the COMMIT phase, react handles all effects generated during the coordination process.

The type of effect

React defines many types of effects, as follows:

  • Placement
  • Update
  • PlacementAndUpdate
  • Ref
  • Deletion
  • Snapshot
  • Passive
  • Layout
  • .

(We have listed only a few of the effects that we often encounter in our daily development. Some of the unlisted effects are less likely to be encountered, and some will be covered in a later article.)

Based on the name above, we can probably guess what these effects stand for:

  • Placement, which only applies to DOM type Fiber nodes, indicates that nodes need to be moved or added.

    When a Fiber node marks Placement, you need to do the following during the COMMIT phase:

    • If the node is an add operation, we need to add a new DOM node through the createElement/appendChild/insertBefore native apis.

    • If the node is a move operation, we need to move an existing DOM node with appendChild/insertBefore;

  • Update: The fiber node needs to be updated for all types of fiber nodes.

    Fiber nodes need to be marked with Update as follows:

    • The props of a DOM type node has changed;
    • Class component requires mount, and defines componentDidMount;
    • Update (componentDidUpdate); update (props/State);
    • Function components need to mount, and use useEffect, useLayoutEffect;
    • Update the props or state of the function component, and useEffect and useLayoutEffect are defined.
    • .

    When the Fiber node is marked Update, you need to do the following during the COMMIT phase:

    • Dom type node, update dom node attributes;
    • Class component node, if mount, triggers componentDidMount; For update, componentDidUpdate is triggered.
    • Function component node, trigger last useEffect, useLayoutEffect return destory, and execute this callback;
  • PlacementAndUpdate, which only applies to DOM fiber nodes, indicates that the node has moved and the props have changed.

    When fiber node marks PlacementAndUpdate, move an existing DOM node with appendChild/insertBefore in the COMMIT phase and modify the dom node attributes.

  • Ref: indicates that the node has Ref and needs to be initialized or updated.

    When fiber node marks Ref, class component instances and DOM elements need to be assigned to ref.current during commit.

  • Deletion indicates that fiber nodes of all types need to be removed.

    When the fiber node is marked Deletion, perform the following operations during the commit phase:

    • Use removeChild to remove the DOM node to be deleted.
    • Trigger the componetWillUnMount life cycle method for the class component and its children to be removed;
    • To trigger the last update of the function component and its sub-components to be removed, the destory method generated by useEffect and useLayoutEffect is executed.
    • Set the ref. Current reference to null;
  • Fiber node is a class component called Snapshot.

    The Snapshot is marked when the class component Fiber Node is mounted or updated and the getSnapshotBeforeUpdate method is defined.

    When a Fiber node is marked with Snapshot, the getSnapshotBeforeUpdate method needs to be triggered during the COMMIT phase.

  • Passive: Mainly for fiber node, indicating that useEffect is used.

    When a function component is mounted or updated and useEffect hook is used, the Fiber node is marked as Passive.

    When the Fiber node is marked Passive, do the following during the COMMIT phase:

    • The destory returned from the previous useEffect is executed first.
    • UseEffect callback when this update is triggered asynchronously;
  • Layout, mainly for the function component fiber node, indicates that the function component uses useLayoutEffect.

    When a function component is mounted or updated and useLayoutEffect hook is used, the Fiber node is marked with Layout.

    When the Fiber node is marked with Layout, you need to do the following during the COMMIT phase:

    • The destory returned from the last useLayoutEffect is executed first.

    • Synchronize the useLayoutEffect callback when this update is triggered;

React uses binary numbers to declare effects, such as Placement 2 (0000 0010) and Update 4 (0000 0100). A fiber node can mark multiple effect at the same time, such as function component props change and use the useEffect hooks, so you can use the Placement | Update = 516 (operator) to mark.

Effect of collection

If a Fiber node is marked with effect, react collects the fiber node after it has been coordinated. When the whole fiber tree is coordinated, all the marked Fiber nodes are collected together.

The collected fiber nodes are stored in a single linked list structure. FirstEffect points to the first fiber node marked effect, and lastEffect points to the last fiber node. The nodes are connected through the nextEffect pointer.

Since the coordination sequence of Fiber Tree is depth-first, and the coordination sequence is child node, brother node of child node and parent node, the collection sequence of Fiber nodes marked with effect is also child node, brother node of child node and parent node.

This explains why the componentDidUpdate and componentDidMount lifecycle methods are executed first for the children and then for the parents.

Effect of processing

The coordination of fiber tree is completed, and the collection of fiber nodes with effect is completed. The next step is to deal with the fiber nodes with effect.

The processing of effect is divided into three stages, which are as follows from front to back:

  1. Before mutation stage (before DOM operation)
  2. Mutation stage (DOM operation)
  3. Layout stage (after DOM manipulation)

Different stages process different kinds of effects. At each stage, React starts at the head of the effect list, -Firsteffect, and proceeds through the Fiber node until it reaches lastEffect.

Before mutation stages

The main work of the before mutation stage is to deal with fiber nodes tagged with Snapshot.

Start with firstEffect and iterate through the Effect list. If fiber node has Snapshot flag, trigger getSnapshotBeforeUpdate.

Mutation stages

The main work of mutation stage is to deal with fiber nodes with Deletion markers and DOM type fiber nodes with Placement, PlacementAndUpdate, and Update markers.

In this stage, it involves the updating, adding, moving and deleting of DOM nodes, the triggering of componentWillUnmount and destory methods caused by the deletion of component nodes, and the reset of ref references caused by the deletion of nodes.

The dom node update operation is relatively simple, and the main operations are as follows:

  • Modify attR of DOM node through native API setAttribute and removeArrribute.
  • Modify the style of the DOM node directly.
  • Modify the innerHtml and textContent of the DOM node directly.

Adding and moving DOM nodes is a bit more complicated.

If the new (moved) node is the last child of the parent node, then the appendChild method can be used directly. But if it’s not the last node, you need to use the insertBefore method. To use the insertBefore method, you must provide a DOM node for positioning.

The whole process is illustrated by a diagram:

Nodes A and C need to be moved, and nodes E and F need to be added.

Process of adding E:

The process of moving A:

The process of moving C:

Process of adding F:

The processing of nodes marked Deletion was also complicated, and many situations were considered:

  • If the node is a DOM node, use removeChild to remove it.
  • If the node is a component node, the execution of destory methods of componentWillUnmount and useEffect is triggered.
  • If there were component nodes in the child nodes of the node marked Deletion, depth-first traversal of the child nodes would trigger the execution of componentWillUnmount and useEffect destory methods of the child nodes in turn.
  • If the node marked Deletion and its child nodes are associated with the ref reference, empty the ref reference, and ref. Current = null(also depth-first traversal).

This explains why the comonentWillUnmount and deStory methods fire in the order of the first parent node and then the child node.

Layout stage

The main job of the Layout stage is to process the component nodes with the UPDATE tag and all nodes with the REF tag.

Work contents are as follows:

  • If the class component node is a mount operation, trigger componentDidMount; For update, componentDidUpdate is triggered.
  • If the function component node mount operation, trigger the useLayoutEffect callback; In the case of update, the deStory generated by the previous update is triggered and the callback is triggered.
  • UseEffect of asynchronous scheduling function components;
  • If the component node is associated with a ref reference, initialize ref.current;

Note that useEffect callback and deStory are both asynchronous and trigger only after the browser has completed rendering.

Write in the last

This concludes the article.

Finally, we make a summary of this paper:

  • Every time react updates, the Fiber Tree coordinates, finds the changed Fiber node, flags it, and collects the effect. After fiber Tree coordination is completed, the collected effect will be processed.

  • Depth-first traversal for Fiber Tree coordination.

  • The nodes of workInProgress Fiber Tree can be generated in three ways: reuse current Fiber node, clone current Fiber node, and create new Fiber node.

  • In coordination, if the render method of component node and sub-component is not triggered, the sub-node can directly reuse the Current Fiber node, otherwise, diff algorithm is used to determine how to create the sub-node.

  • Diff algorithm only compares children of matched parent nodes, not across parent nodes.

  • If the react Element and current Fiber node have the same key and type, copy the current Fiber node. If the React Element and current Fiber node have the same key and type, copy the current Fiber node.

  • After fiber Tree coordination is complete, a single linked list is used to collect fiber nodes marked with effect. In the linked list, the order of fiber nodes is child node, sibling node, and parent node.

The resources

  • React
  • React Technology revealed

portal

  • React series 1: How react works