So sánh useEffect, useLayoutEffect và useEffectEvent trong React

Ở bài viết này, hãy cùng nhau khám phá các hook tìm nạp dữ liệu của React - useEffect, useLayoutEffect, và useEffectEvent - so sánh các chức năng của chúng để triển khai ứng dụng hiệu quả.

Lập trình React

Hook của React mang tới cách quản lý hiệu quả các tác động phụ trong thành phần React. 3 trong số hook phổ biến nhất là useEffect, useLayoutEffect và useEffectEvent. Mỗi hook có cách dùng riêng, hãy cùng nhau so sánh chúng để có lựa chọn phù hợp khi bạn lập trình React nhé!

useEffect

useEffect là một hook cơ bản trong React, cho phép bạn triển khai các hiệu ứng phụ như chỉnh sửa DOM, hoạt động không đồng bộ, và tìm nạp dữ liệu trong các thành phần chức năng. Hook này là một hàm có hai đối số: effect function - hàm hiệu ứng và dependency array - mảng phụ thuộc.

Effect function chứa code triển khai hiệu ứng phụ, và dependency array quyết định khi nào hiệu ứng chạy. Nếu mảng phụ thuộc trống, hàm effect chỉ chạy một lần lần kết xuất ban đầu của thành phần. Nếu không, effect function chạy bất cứ khi nào giá trị trong mảng phụ thuộc thay đổi.

Đây là ví dụ về cách dùng hook useEffect để tìm nạp dữ liệu:

import React from "react";

function App() {
  const [data, setData] = React.useState([]);

  React.useEffect(() => {
    fetch("<https://jsonplaceholder.typicode.com/posts>")
      .then((response) => response.json())
      .then((data) => setData(data));
  }, []);

  return (
    <div className="app">
      {data.map((item) => (
        <div key={item.id}>{item.title}</div>
      ))}
    </div>
  );
}

export default App;

Code này chứng minh một thành phần App tìm nạp dữ liệu từ API bên ngoài bằng hook useEffect. Effect function của useEffect tìm nạp dữ liệu mẫu từ API JSONPlaceholder. Sau đó, nó phân tích phản hồi JSON và đặt dữ liệu được truy xuất về trạng thái data.

Với trạng thái data, thành phần App hiện thuộc tính title của từng mục trong trạng thái.

Đặc điểm của hook useEffect

  • “Thân thiện” với hoạt động không đồng bộ, khiến quá trình tìm nạp dữ liệu thuận tiện hơn.
  • Chạy sau khi render thành phần, đảm bảo hook không chặn UI.
  • Triển khai dọn dẹp bằng cách trả về một hàm.

useLayoutEffect

useLayoutEffect tương tự như hook useEffect nhưng chạy đồng bộ sau toàn bộ đột biến DOM. Điều này có nghĩa nó chạy trước khi trình duyệt có thể che màn hình, khiến nó phù hợp với các nhiệm vụ cần kiểm soát chính xác trên bố cục và kiểu DOM, như đo kích thước của một phần tử, chỉnh lại kích cỡ hay tạo chuyển động cho vị trí của nó.

Dưới đây là một ví dụ về cách dùng hook useLayoutEffect để thay đổi chiều rộng của thành phần nút bấm:

import React from "react";

function App() {
  const button = React.useRef();

  React.useLayoutEffect(() => {
    const { width } = button.current.getBoundingClientRect();

    button.current.style.width = `${width + 12}px`;
  }, []);

  return (
    <div className="app">
      <button ref={button}>Click Me</button>
    </div>
  );
}

export default App;

Khối code trên tăng chiều rộng của thành phần nút bấm lên 12 pixel bằng cách dùng hook useLayoutEffect. Điều này đảm bảo chiều rộng nút bấm đó tăng lên trước khi nút hiện trên màn hình.

Đặc điểm nổi bật của hook useLayoutEffect

  • Triển khai đồng bộ, có khả năng chặn UI nếu thao tác bên trong nó nặng.
  • Lựa chọn tốt nhất để đọc và ghi trực tiếp dữ liệu vào DOM.

useEffectEvent

useEffectEvent là một hook React, giải quyết các vấn đề phụ thuộc của hook useEffect. Nếu đã quen với useEffect, bạn cần biết mảng phụ thuộc của nó có thể phức tạp. Đôi khi, bạn phải đặt nhiều giá trị hơn vào trong mảng phụ thuộc thật sự cần thiết.

Ví dụ:

import React from "react";

function App() {
  const connect = (url) => {
    // logic for connecting to the url
  };

  const logConnection = (message, loginOptions) => {
    // logic for logging the connection details
  };

  const onConnected = (url, loginOptions) => {
    logConnection(`Connected to ${url}`, loginOptions);
  };

  React.useEffect(() => {
    const device = connect(url);
    device.onConnected(() => {
      onConnected(url);
    });

    return () => {
      device.disconnect();
    };
  }, [url, onConnected]);

  return <div></div>;
}

export default App;

Code này cho thấy thành phần App quản lý kết nối tới dịch vụ bên ngoài. Hàm connect kết nối tới một URL cụ thể, còn hàm logConnection ghi lại chi tiết kết nối. Cuối cùng, hàm onConnected gọi logConnection để ghi lại một thông báo kết nối thành công khi thiết bị kết nối.

Hook useEffect gọi hàm kết nối, sau đó thiết lập một hàm callback onConnected để chạy khi device kích hoạt sự kiện onConnected. Callback này ghi một thông báo kết nối. Nó trả về một hàm dọn dẹp kích hoạt khi thành phần này được ngắt kết nối. Hàm dọn dẹp chịu trách nhiệm ngắt kết nối thiết bị đó.

Mảng phụ thuộc có biến url và hàm onConnected. Thành phần App sẽ tạo hàm onConnected trên mỗi render. Điều này sẽ khiến hàm useEffect chạy trên một vòng lặp mà liên tục render thành phần App.

Hiện có nhiều cách xử lý vấn đề lặp useEffect. Tuy nhiên, cách hiệu quả nhất để làm việc này mà không thêm các giá trị không cần thiết cho mảng phụ thuộc là qua hook useEffectEvent.

import React from "react";

function App() {
  const connect = (url) => {
    // logic for connecting to the URL
  };

  const logConnection = (message, loginOptions) => {
    // logic for logging the connection details
  };

  const onConnected = React.useEffectEvent((url, loginOptions) => {
    logConnection(`Connected to ${url}`, loginOptions);
  });

  React.useEffect(() => {
    const device = connect(url);
    device.onConnected(() => {
      onConnected(url);
    });

    return () => {
      device.disconnect();
    };
  }, [url]);

  return <div></div>;
}
export default App;

Bằng cách đóng gói hàm onConnected với hook useEffectEvent, hook useEffectEvent luôn có thể đọc giá trị mới nhất của tham số messageloginOptions trước khi chuyển nó sang hook useEffect. Điều này có nghĩa useEffect không cần dựa vào hàm onConnected hay giá trị đã chuyển sang nó.

useEffectEvent hữu ích khi bạn muốn useEffect phụ thuộc vào một giá trị cụ thể, mặc dù hiệu ứng này kích hoạt một sự kiện cần các giá trị khác mà bạn không muốn dùng làm các phần phụ thuộc trong useEffect.

Đặc điểm của hook useEffectEvent

  • Phù hợp nhất cho các hiệu ứng dụng hướng sự kiện.
  • Hook useEffectEvent không hoạt động với trình xử lý sự kiện như onClick, onChange…

Tóm lại, mỗi hook tìm nạp dữ liệu trên phù hợp cho các tình huống khác nhau:

  • Tìm nạp dữ liệu: useEffect là lựa chọn tuyệt vời.
  • Thao tác DOM trực tiếp: Nếu bạn cần thực hiện các thay đổi đồng bộ đối với DOM trước khi repaint, hãy chọn useLayoutEffect.
  • Hoạt động gọn nhẹ: Đối với các thao tác không có nguy cơ chặn giao diện người dùng, bạn có thể thoải mái sử dụng useEffect.
  • Hiệu ứng phụ hướng sự kiện: Dùng hook useEffectEvent để đóng gói các sự kiện và hook useEffect để chạy hiệu ứng phụ.

Hook ReactJS mở ra một thế giới đa khả năng và hiểu sự khác biệt giữa các hook useEffect, useLayoutEffect, và useEffectEvent có thể tác động đáng kể tới cách bạn xử lý hiệu ứng phụ và thao tác DOM.

Thứ Sáu, 20/10/2023 08:24
31 👨 287
0 Bình luận
Sắp xếp theo