useLayoutEffect vs useEffect - Der Unterschied

Manchmal wollen wir Operationen außerhalb des Datenflusses durchführen, wie z. B. die Interaktion mit einer API. Diese Vorgänge werden als Seiteneffekte bezeichnet. In diesem Artikel werden wir untersuchen, wie man in React mit Seiteneffekten umgeht, indem wir einen Hook namens useLayoutEffect verwenden.

Fügen Sie Ihrem Webflow-Projekt in wenigen Minuten Mitgliedschaften hinzu.

Los geht's

Über 200 kostenlose, klonbare Webflow-Komponenten. Keine Anmeldung erforderlich.

Ansicht Bibliothek

Fügen Sie Ihrem React-Projekt in wenigen Minuten Mitgliedschaften hinzu.

Los geht's

React’s data flow process is pretty straightforward. It breaks down a user interface into components, builds a tree of elements, and makes necessary updates to the DOM based on modifications in those components. However, sometimes we want to perform operations outside the scope of this data flow process, like interacting with an API. These operations are called side effects.

A “side effect” is anything that results in observable changes after a function has finished running, apart from the return value of the function itself. 

Common side effects include network requests, data-fetching, and manual DOM mutations.

In this article, we will explore how to handle side effects in React using a hook called useLayoutEffect.

Prerequisites

To understand this article, we need the following:

  • Good knowledge of functional programming using JavaScript and React.

Experience with React useEffect.

What is useLayoutEffect?

According to React’s official documentation:

  • The signature is identical to useEffect, but it fires synchronously after all DOM mutations.

To understand this better, let’s take a look at useEffect's function signature:


useEffect(
 // callback function,
[ /* dependencies */ ]
);

useEffect takes in two arguments:

  • A callback function containing the side effect logic.
  • An array of dependencies that trigger the callback when updated between renders. If there are no dependencies, it stays as an empty array.

Let’s compare it to useLayoutEffect's function signature:


useLayoutEffect(
 // callback function,
[ /* dependencies */ ]
);

useLayoutEffect vs useEffect - the difference

As we’ve seen so far, both hooks are identical and, in most cases, can even be used interchangeably. But, there’s one key difference between them: execution time. Take a look at the diagrams below:

In useEffect, when a user triggers a render (by updating state or props), React updates the screen, and the useEffect callback function runs asynchronously in the background.

In useLayoutEffect, the callback function runs synchronously before the screen is updated. 

Let’s see an example that illustrates these concepts better. Take a look at the code below:


const Comparison = () => {
  // with useEffect
  useEffect(() => {
    console.log('This is useEffect');
  }, []);

  // with useLayoutEffect
  useLayoutEffect(() => {
    console.log('This is useLayoutEffect');
  }, []);

  return <div>Comparison</div>;
};

export default Comparison;

In the code above:

  • We created a component implementing the useEffect hook and the useLayoutEffect hook. 
  • Each hook logs a string to the console to help us identify the hook type. 

Let’s take a look at the console:

As we can see here, since useLayoutEffect runs synchronously before the DOM updates, its result will be ready for the console first. 

After the DOM updates, useEffect will run asynchronously and display its results on the console.

When to use useLayoutEffect

In most cases, to make our app faster and more performant, it is recommended to handle side effects with useEffect since it executes after the DOM updates, preventing blocking issues on the browser.

However, when we need to do something based on the layout of our DOM and there are visual inconsistencies with useEffect, it is best to use useLayoutEffect.

For example, let’s create a button that will display a colored rectangle when clicked. 

Here’s its implementation with useEffect:


import React, { useEffect, useRef, useState } from 'react';

const RenderRectangle = () => {
  const [display, setDisplay] = useState(false);
  const rectangle = useRef();
  
  useEffect(() => {
    if (rectangle.current == null) return;
    rectangle.current.style.backgroundColor = 'green';
    rectangle.current.style.marginTop = '20px';
  }, [display]);
  
  return (
    <div>
      <h1>useEffect - Render Rectangle</h1>
      <div>
        <button
          style={{ width: 100, height: 40, borderRadius: 5 }}
          onClick={() => setDisplay(!display)}
        >
          {display ? 'Hide' : 'Show'}
        </button>
        {/* Rectangle */}
        {display && (
          <div
            style={{ width: 100, height: 50, backgroundColor: 'red' }}
            ref={rectangle}
          ></div>
        )}
      </div>
    </div>
  );
};

export default RenderRectangle;

In this code: 

  • We set the default state of the rectangle to false using useState.
  • We used useRef to refer to our rectangle div, allowing us to apply side effects on it using useEffect.
  • We wrote some markup for displaying the rectangle at the click of the button. The button will change display's state from true to false and vice versa.
  • We used useEffect to style the rectangle after render.

Here’s the result:

Notice that when the button is clicked, the rectangle displays with its initial background color of red, and quickly changes to green from the useEffect. The top margin of the rectangle also gets updated. 

For a smoother effect, it will be better to use useLayoutEffect like this:


import React, { useLayoutEffect, useRef, useState } from 'react';

const RenderRectangle = () => {
  const [display, setDisplay] = useState(false);
  const rectangle = useRef();

  useLayoutEffect(() => {
    if (rectangle.current == null) return;
    rectangle.current.style.backgroundColor = 'green';
    rectangle.current.style.marginTop = '20px';
  }, [display]);

  return (
    <div style={{ width: '100%', maxWidth: '800px', margin: 'auto' }}>
      <h1>useLayoutEffect - Render Rectangle</h1>
      <div>
        <button
          style={{ width: 100, height: 40, borderRadius: 5 }}
          onClick={() => setDisplay(!display)}
        >
          {display ? 'Hide' : 'Show'}
        </button>
        {/* Rectangle */}
        {display && (
          <div
            style={{ width: 100, height: 50, backgroundColor: 'red' }}
            ref={rectangle}
          ></div>
        )}
      </div>
    </div>
  );
};

export default RenderRectangle;

Here’s the result:

As we can see, there are no color or position glitches in this one.

Schlussfolgerung

In this article, we learned what useLayoutEffect is used for, when to use it, and how. For most use cases, it is a good idea to stick with useEffect, but feel free to use useLayoutEffect as the need arises. 

To see the demos used in the article, check the CodeSandbox below:

https://codesandbox.io/embed/uselayouteffect-fenjtg?fontsize=14&hidenavigation=1&theme=dark

INHALTSVERZEICHNIS
Göttlicher Orji
Was ist Memberstack?

Autorisierung und Zahlungen für Webflow-Websites

Fügen Sie Ihrer Webflow-Website Logins, Abonnements, Gated Content und vieles mehr hinzu - einfach und vollständig anpassbar.

Mehr erfahren
Klicken Sie hier, um Memberstack live zu testen
Mit dem Bau beginnen

Probieren Sie Memberstack aus und entdecken Sie, was Sie bauen können!

Memberstack ist 100% kostenlos, bis Sie bereit sind, zu starten - worauf warten Sie also noch? Erstellen Sie Ihre erste App und beginnen Sie noch heute mit der Entwicklung.