The difference between useEffect and useLayoutEffect in React

The difference between useEffect and useLayoutEffect in React

Prerequisites

We can divide React's workflow into several parts:

  1. Rendering phase: mainly generates Fiber nodes and builds a complete Fiber tree
  2. Commit phase: In the previous render phase, a side effect list will be generated on the rootFiber, and the DOM operations of the application will be performed in this phase

The work in the commit phase is mainly divided into three parts, and the corresponding function names in the source code are:

  • commitBeforeMutationEffects phase: mainly handles some related operations before performing DOM operations
  • commitMutationEffects phase: performing DOM operations
  • commitLayoutEffects phase: mainly handles some related operations after performing DOM operations

The difference between useEffect and useLayoutEffect lies mainly in the processing of these three stages. The conclusion is: useEffect will execute its response function and the last destruction function asynchronously, while useLayoutEffect will execute its response function and the last destruction function synchronously, which will block DOM rendering.

useEffect

commitBeforeMutationEffects

In this stage, useEffect will focus on the following sentence:

function commitBeforeMutationEffects() {
  while (nextEffect$1 !== null) {
    // A series of assignment operations are omitted. The flags here should be taken from the flags of the effect of the corresponding FunctionComponent. For specific implementation, please refer to the source code var flags = effect.flags;

  // Processing life cycle if ((flags & Snapshot) !== NoFlags) {
      setCurrentFiber(nextEffect$1);
      commitBeforeMutationLifeCycles(current, nextEffect$1);
      resetCurrentFiber();
    }

 // This if statement only checks if useEffect is true and useLayoutEffect is false
    if ((flags & Passive) !== NoFlags) {
      // If there are passive effects, schedule a callback to flush at
      // the earliest opportunity.
      if (!rootDoesHavePassiveEffects) {
        rootDoesHavePassiveEffects = true;
 // This is why useEffect is asynchronous. React will schedule flushPassiveEffects after DOM operation.
        scheduleCallback(NormalPriority, function () {
          flushPassiveEffects();
          return null;
        });
      }
    }

    nextEffect$1 = nextEffect$1.nextEffect;
  }
}

commitMutationEffects

During this phase, React will perform a series of DOM node updates and then execute a method: commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);

Then a Functional Component with useEffect does not conform to the unmount judgment logic at this stage, so the unmount operation will not be performed at this place.

commitLayoutEffects

At this stage, there is still a very important method: commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);

This if judgment is the same as the if judgment in the previous stage. useEffec will not perform any operation in this judgment.

Subsequent stages

After completing commitLayoutEffects, there is one more operation:

if (rootDoesHavePassiveEffects) {
    // This commit has passive effects. Stash a reference to them. But don't
    // schedule a callback until after flushing layout work.
    rootDoesHavePassiveEffects = false;
    rootWithPendingPassiveEffects = root;
    pendingPassiveEffectsLanes = lanes;
    pendingPassiveEffectsRenderPriority = renderPriorityLevel;
  }

That is, rootWithPendingPassiveEffects is set to root. The reason for this is related to the next flushPassiveEffects asynchronous scheduling registered by useEffect in the first phase commitBeforeMutationEffects. Let's look at the following flushPassiveEffects implementation:

function flushPassiveEffectsImpl() {
 if (rootWithPendingPassiveEffects === null) {
    return false;
  }
 //Omit a series of performance tracking operations commitPassiveUnmountEffects(root.current);
  commitPassiveMountEffects(root, root.current);
}


As can be seen from the above code snippet, the scheduling callback registered by useEffect in the first phase will be unmounted and mounted after the page is updated. It is worth mentioning that the effect in this callback is registered in the commitLayoutEffects phase.

useLayoutEffect

In fact, according to our analysis of useEffect, in the if judgments in the commitMutationEffects and commitLayoutEffects stages, useLayoutEffect is judged by if, so in the commitMutationEffects stage, the last destruction function of useLayoutEffect is executed synchronously, and in the commitLayoutEffects stage, the execution function of useLayoutEffect this time is executed synchronously, and the destruction function is registered.

in conclusion

So far, we have roughly reviewed the code of the commit phase and analyzed why useEffect is executed asynchronously and useLayoutEffect is executed synchronously. I did not post too much specific code in the article because these are all variable. The real process overview and the mental model of the React team designing this mechanism require us to slowly become familiar with it through continuous debugging of code and understanding.

What I am interested in later is the implementation of hooks. Among them, I will focus on the source code of the more critical useReducer to see if I can write a simple version and put it in the Alipay applet to implement a custom Alipay hooks for daily productivity development.

This is the end of this article about the difference between useEffect and useLayoutEffect in React. For more relevant React useEffect useLayoutEffect content, please search 123WORDPRESS.COM's previous articles or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • A brief discussion on the pitfalls of react useEffect closure
  • Understanding and using React useEffect

<<:  Solve the problems encountered during the installation of Mysql 8.0.17 winx64 version

>>:  What are the differences between CDN, SCDN, and DCDN for website acceleration? How to choose?

Recommend

How to lock a virtual console session on Linux

When you are working on a shared system, you prob...

Detailed explanation of MYSQL database table structure optimization method

This article uses an example to illustrate the me...

How to set remote access permissions in MySQL 8.0

The previous article explained how to reset the M...

Some CSS questions you may be asked during an interview

This article is just to commemorate those CSS que...

The difference between Vue interpolation expression and v-text directive

Table of contents 1. Use plugin expressions 2. Us...

Share JS four fun hacker background effect codes

Table of contents Example 1 Example 2 Example 3 E...

Ubuntu 15.04 opens mysql remote port 3306

Ubuntu 15.04 opens MySQL remote port 3306. All th...

CSS3 realizes bouncing ball animation

I usually like to visit the special pages or prod...

How to import Excel files into MySQL database

This article shares with you how to import Excel ...

Implementation code for using CSS text-emphasis to emphasize text

1. Introduction In the past, if you wanted to emp...

Windows Server 2016 Quick Start Guide to Deploy Remote Desktop Services

Now 2016 server supports multi-site https service...

Some common properties of CSS

CSS background: background:#00ffee; //Set the back...

Solve the problem of MySql8.0 checking transaction isolation level error

Table of contents MySql8.0 View transaction isola...

In-depth understanding of Vue's plug-in mechanism and installation details

Preface: When we use Vue, we often use and write ...