1
头图

Hi everyone, I'm Kasong.

Let's look at this article React internal Effects List mechanism reconstruction of cause and effect.

After reading this article, you can grasp the difference and reasons React18 compared to the previous version, Suspense

Welcome to join the human high-quality front-end frame group , take flight

What are side effects

The simple React can be summarized as:

  1. Trigger update
  2. stage: Calculate the side effects caused by the update of 161a97a2f5ae49
  3. commit phase: side effects of

side effects include many types, such as:

  • Placement refers to the insertion and movement of
  • Passive refers to useEffect callback execution
  • ChildDeletion refers to the removal of the child DOM node
  • and many more

The main changes caused by the update to DOM Placement and ChildDeletion .

So how does the render stage save the side effects, and how does the commit stage side effects?

Effects List

Before reconstruction, in the render stage, nodes with side effects will be connected to form a linked list, which is called Effects List .

For example, in the following figure, B, C, and E have side effects of , and the connection forms Effects List :

commit stage does not need to traverse the entire tree from A down, only need to traverse Effects List to find all nodes with side effects and perform corresponding operations.

SubtreeFlags

After the reconstruction, the side effects child node will be bubbled to the SubtreeFlags attribute of the parent node.

For example, the side effects contained in B, C, and E are as follows:

The bubbling process is as follows:

  1. The side effect of B’s Passive , bubbled to A, A.SubtreeFlags contains Passive
  2. E's side effect is Placement , bubbled to D, D.SubtreeFlags contains Placement
  3. D bubbles to C, C.SubtreeFlags contains Placement
  4. C’s side effect is Update , C.SubtreeFlags contains Placement , C bubbling to A
  5. The final A.SubtreeFlags contains Passive , Placement , Update

This means that A's subtree contains these three side effects.

In the commit phase, then according SubtreeFlags Finding layers side node and perform a corresponding operation.

It can be seen that SubtreeFlags needs to traverse the tree, while Effects List only needs to traverse the linked list, which is more efficient. So React be refactored?

Suspense

The answer is: SubtreeFlags operating traversal subtree although the ratio Effects List need to traverse more nodes, but React18 in a new feature just need traverse the subtree .

This feature is Suspense .

Suspense is v16 to provide functionality, but v18 later, when concurrent open function, Suspense previous versions of the behavior is different.

Consider the following components:

<Suspense fallback={<h3>loading...</h3>}>
  <LazyCpn />
  <Sibling />
</Suspense>

Wherein LazyCpn using React.lazy wrapped asynchronous loading assembly.

Sibling code for 061a97a2f5b36e is as follows:

function Sibling() {
  useEffect(() => {
    console.log("Sibling effect");
  }, []);

  return <h1>Sibling</h1>;
}

Since Suspense will wait for the asynchronous request in the descendant components to complete before rendering, when the code runs, the page will first render fallback :

<h3>loading...</h3>

But Sibling not asynchronous! This reflects the difference between the old and new version React

Differences between the old and new versions of React

Recall the working principle React introduced at the beginning:

  1. Trigger update
  2. phase: The coordinator calculates the side effects caused by the 161a97a2f5b497 update
  3. commit stage: the renderer executes side effects

Before enabling concurrency, React guarantees that a render stage corresponds to a commit stage.

So in the above example, although due LazyCpn in the request led to Suspense rendering fallback , but does not prevent Sibling rendering, it will not prevent Sibling in useEffect executed.

The console will still print Sibling effect .

At the same time, in order to visually appear that Sibling not rendered, the DOM node of Sibling rendered by will be set to display: none :

But this is actually quite hack . After all, according to Suspense , if the descendant components have asynchronously loaded content, then only fallback should be rendered (rather than the content of display: none at the same time)

Therefore, in the new version, a separate process is for the subtree 161a97a2f5b5cf that is not displayed in Suspense in , neither rendering the content of display: none useEffect callback:

The basis for this part of the process is to change the commit phase, which means returning to the Effects List mentioned in the opening refactoring to subtreeFlags .

You can intuitively feel the difference between the new version and the old version Suspense online Demo

Summarize

Today we learned a little knowledge of React

It is worth mentioning that, for Suspense this improvement, as React bring a new internal component type - Offscreen Component .

In the future, he may be the basis for the React version keep-alive


卡颂
3.1k 声望16.7k 粉丝