开源日报每天推荐一个 GitHub 优质开源项目和一篇精选英文科技或编程文章原文,坚持阅读《开源日报》,保持每日学习的好习惯。

2024年1月24日,开源日报第1084期:
今日推荐开源项目:《cypress》
今日推荐英文原文:《From My Experience: useEffect vs useLayoutEffect in React》


开源项目

今日推荐开源项目:《cypress》传送门:项目链接

推荐理由: 快速、简便且可靠的测试适用于在浏览器中运行的任何内容

网站直达:cypress.io


英文原文

今日推荐英文原文:From My Experience: useEffect vs useLayoutEffect in React

推荐理由:useEffect 和 useLayoutEffect 是 React 中处理副作用的关键 Hooks。前者适用于大多数场景,执行于浏览器绘制后,用于数据获取和订阅,而LayoutEffect用于需要在 DOM 变更之前同步操作的场景


From My Experience: useEffect vs useLayoutEffect in ReactIntroduction 🌟

With the introduction of hooks in React 16.8, the landscape of writing functional components changed dramatically. Among these, useEffect and useLayoutEffect are particularly important for handling side effects in your code. They might look similar at first, but there are some important differences between them. In this blog, we'll look at these differences in a clear and straightforward way. We'll help you understand when to use useEffect and when useLayoutEffect might be a better choice for your React projects.

Let's get started on this practical exploration of these two essential React hooks.

What is useEffect? 🔍

useEffect is a React hook that allows you to perform side effects in your functional components. Side effects are essentially any operations that affect something outside the scope of the function being executed. This can include data fetching, subscriptions, manually changing the DOM, and more.

Remember, 99% of the time, useEffect is the hook you'll want to use.

How to Use useEffect: 🚀

When you use useEffect, you tell React to do something after the render. React will remember the function you passed, and call it later after performing the DOM updates.

Syntax of useEffect:

useEffect(() => {
  // Code for your side effect goes here.
}, [dependencies]);

The second argument, [dependencies], is an array of dependencies. React will only re-run the side effect if one of the dependencies has changed. If you pass an empty array ([]), the side effect runs once after the initial render, making it similar to componentDidMount in class components.

What is useLayoutEffect? 🤔

useLayoutEffect is another React hook that is similar to useEffect but with a key difference in its execution timing. It is used for operations that need to synchronize with the DOM, such as directly manipulating the DOM or adjusting the layout before the browser paints.

When to Use useLayoutEffect: 📐

useLayoutEffect should be used when you need to make DOM changes before the screen is updated. This is crucial in scenarios where you want to avoid visual glitches, like flickering, that can occur if you manipulate the DOM after it has been painted on the screen.

Syntax of useLayoutEffect:

useLayoutEffect(() => {
  // Code that interacts with the DOM.
}, [dependencies]);

Like useEffect, it also takes a dependency array as the second argument.

Comparing useEffect and useLayoutEffect in Action ⚖️

After exploring useEffect and useLayoutEffect separately, it's helpful to see them in action within the same component. This comparison will give us a clearer understanding of their execution order and behavior.

Let’s create a single functional component that includes both useEffect and useLayoutEffect. We will add console logs to each hook to observe the order in which they execute.

import React, { useEffect, useLayoutEffect } from 'react';

const Home = () => {

  useLayoutEffect(() => {
    console.log('useLayoutEffect - Runs first, but after DOM mutations');
  }, []);

  useEffect(() => {
    console.log('useEffect - Runs second, after the browser has painted');
  }, []);

  return (
    <div>Hello, React Hooks!</div>
  );
};

export default Home;

In this component, we have both useLayoutEffect and useEffect with empty dependency arrays, meaning they should run after the initial render.

img

useEffect vs useLayoutEffect

  1. useLayoutEffect: This hook runs first. It is fired after all DOM mutations are complete but before the browser has had a chance to paint. This makes it ideal for any DOM manipulations or calculations that need to happen right after the DOM updates but before the user sees anything. The console log inside useLayoutEffect will be the first one to appear.
  2. useEffect: This hook runs after useLayoutEffect. It fires after the component render cycle has completed and after the screen has been updated. This behavior means useEffect is best for tasks that do not require immediate, synchronous updates to the DOM, like API calls or setting up subscriptions. The console log inside useEffect will appear after the one from useLayoutEffect.

While theoretically, useEffect might cause a flickering effect due to its asynchronous nature (executing after the browser has painted), in practice, observing a noticeable flicker can be difficult. Visually, useEffect and useLayoutEffect often appear to behave similarly, especially for less complex DOM updates.

Practical Examples: useEffect and useLayoutEffect in Action 💫

To better grasp the nuances of useEffect and useLayoutEffect, let's dive into some practical examples. These will illustrate how each hook can be effectively utilized in different situations.

It's important to note that in many cases, especially in simple scenarios or with modern, high-performance browsers, these differences might not be visually apparent.

1️⃣ useEffect for Data Fetching🌐📈

Data fetching is a common use case for useEffect. It allows you to request and load data from an API when your component is rendered.

Here’s a full example of a React component that uses useEffect to fetch data from the JSONPlaceholder API, a free fake online REST API:

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

const App = () => {
  const [data, setData] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch('https://jsonplaceholder.typicode.com/posts');
        const jsonData = await response.json();
        setData(jsonData);
      } catch (error) {
        console.error('Error fetching data: ', error);
      }
    };
    fetchData();
  }, []); 
  return (
    <div>
      <h1>Data Fetched from JSONPlaceholder API</h1>
      <ul>
        {data.map(item => (
          <li key={item.id}>{item.title}</li> 
        ))}
      </ul>
    </div>
  );
};

export default App;

The component renders a list of titles fetched from the API. The empty array in the dependency list of useEffect ensures that the data fetching runs only once, similar to componentDidMount in class components.

2️⃣ useLayoutEffect for DOM Manipulation: 📜

Let’s consider a situation where you want to adjust the scroll position of a list to the top immediately after some state changes. Doing this with useEffect might result in a noticeable flicker, as the adjustment happens after the screen updates. useLayoutEffect solves this by ensuring the adjustment is made before the screen paints.

Here’s an example:

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

const App = () => {
  const [items, setItems] = useState([]);
  const listRef = useRef(null);

  const addItems = () => {
    const newItems = [...Array(5).keys()].map(i => `Item ${i + items.length}`);
    setItems([...items, ...newItems]);
  };

  useLayoutEffect(() => {
    // Adjust the scroll position before the screen updates
    if (listRef.current) {
      listRef.current.scrollTop = 0;
    }
  }, [items]); // Dependency on 'items' state

  return (
    <div>
      <button onClick={addItems}>Add Items</button>
      <ul ref={listRef}>
        {items.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
};

export default App;

In this component:

  • We use useState to create an items state that stores a list of items.
  • A button is provided to add new items to the list.
  • The useLayoutEffect hook is used to scroll the list to the top every time new items are added. This is done before the browser paints the updated UI, preventing any flicker or jump in the scroll position.
  • The ref attribute (listRef) is used to reference the list DOM element for manipulating its scroll position.

This example showcases how useLayoutEffect can be used to make smooth, flicker-free adjustments to the DOM in response to state changes in a React component.

Conclusion ✅

The choice between useEffect and useLayoutEffect often depends on the specific requirements of the DOM operation being performed. While the visual differences might not always be obvious, understanding the internal behavior of these hooks is key to optimizing your React application's performance and ensuring a smooth user experience.

useEffect is your go-to hook for most side effects, especially those that don't require immediate interaction with the DOM, like data fetching or setting up subscriptions. Its ability to react to state and prop changes makes it incredibly versatile for a wide range of use cases.

On the other hand, useLayoutEffect is essential when you need to make synchronous updates in direct response to DOM changes. It's the perfect tool for avoiding visual glitches and ensuring a smooth user experience when manipulating the DOM.


下载开源日报APP:https://openingsource.org/2579/
加入我们:https://openingsource.org/about/join/
关注我们:https://openingsource.org/about/love/