0
0
Lập trình
Admin Team
Admin Teamtechmely

Vòng Đời của useEffect: Đồng Bộ Hóa trong React

Đăng vào 4 tháng trước

• 6 phút đọc

Giới thiệu

Trong các bài viết trước, tôi đã thảo luận về nền tảng của hook useEffect và khi nào không nên sử dụng nó. Trong bài viết này, chúng ta sẽ khám phá vòng đời của useEffect và cách mà nó có thể giúp đồng bộ hóa các thành phần trong React.

useEffect chủ yếu được sử dụng để đồng bộ hóa các thành phần React sau các tác động phụ, những thao tác diễn ra bên ngoài hệ thống render chính của React. Effect sẽ chạy sau khi thành phần được gắn vào (mounted), vì vậy chúng ta cần xem xét vòng đời của các thành phần React và vòng đời của useEffect một cách riêng biệt. Tài liệu React đã nhấn mạnh điều này một cách rõ ràng.

Vòng đời của các thành phần React

Các thành phần React trải qua ba giai đoạn: gắn vào (mount), cập nhật (update) và gỡ bỏ (unmount). Tuy nhiên, useEffect cần phải đồng bộ hóa ít thường xuyên hoặc nhiều thường xuyên hơn chu trình của thành phần.

Ví dụ từ tài liệu React

Dưới đây là một ví dụ từ tài liệu React. Thành phần này có một menu thả xuống, nơi người dùng có thể chọn một ID phòng: general, travel, hoặc music.

javascript Copy
function ChatRoom({ roomId /* "general" */ }) {
  useEffect(() => {
    const connection = createConnection(serverUrl, roomId); // Kết nối với phòng "general"
    connection.connect();
    return () => {
      connection.disconnect(); // Ngắt kết nối khỏi phòng "general"
    };
  }, [roomId]);
}

Mỗi khi roomId thay đổi, Effect sẽ ngừng đồng bộ với roomId cũ và bắt đầu đồng bộ với roomId mới. React sẽ gọi hàm dọn dẹp (cleanup function).

Tách biệt vòng đời của useEffect

Chúng ta nên xem xét các thành phần của React và useEffect một cách độc lập. Tài liệu React nói:

"Luôn tập trung vào một chu trình bắt đầu/dừng tại một thời điểm. Điều này không nên ảnh hưởng đến việc thành phần đang được gắn vào, cập nhật hay gỡ bỏ. Tất cả những gì bạn cần làm là mô tả cách bắt đầu đồng bộ hóa và cách dừng nó. Nếu bạn làm điều này tốt, Effect của bạn sẽ kiên cường với việc được bắt đầu và dừng lại nhiều lần như cần thiết."

Cách thông báo cho React đồng bộ hóa lại

Chúng ta có thể thông báo cho React khi nào cần đồng bộ hóa lại bằng cách cung cấp props hoặc state trong mảng phụ thuộc. Một mảng phụ thuộc rỗng có nghĩa là useEffect chỉ chạy khi thành phần được gắn vào.

Mỗi Effect nên đại diện cho một quá trình đồng bộ hóa riêng biệt

Chúng ta có thể bị cám dỗ để đơn giản hóa mã bằng cách kết hợp các hàm để làm cho nó "sạch sẽ" hơn. Tuy nhiên, chúng ta nên ghi nhớ rằng có thể chúng ta sẽ thêm nhiều tính năng và hàm hơn sau này. Do đó, mỗi useEffect nên chỉ chứa một thao tác logic.

Thành phần ChatRoom có hai thao tác riêng biệt: một là ghi nhận sự truy cập của người dùng vào trang, và thao tác còn lại là kết nối đến máy chủ. Hiện tại, có thể hợp nhất chúng lại vì cả hai đều được kích hoạt khi roomId thay đổi. Tuy nhiên, khi thành phần có nhiều tính năng hơn và mảng phụ thuộc mở rộng, điều này có thể dẫn đến hành vi không mong muốn.

Ví dụ tách biệt các Effect

javascript Copy
function ChatRoom({ roomId }) {
  useEffect(() => {
    logVisit(roomId);
  }, [roomId]);

  useEffect(() => {
    const connection = createConnection(serverUrl, roomId);
    connection.connect();
    return () => {
      connection.disconnect();
    };
  }, [roomId]);
}

Effect nên đồng bộ hóa lại khi các giá trị phản ứng thay đổi

Các giá trị được khai báo trong một thành phần đều là "phản ứng". Điều này không chỉ bao gồm props và state mà còn cả các biến được tính toán dựa trên sự thay đổi của props và state.

Các giá trị phản ứng nên đồng bộ hóa lại với Effect vì chúng thay đổi theo thời gian. Do đó, chúng ta nên bao gồm những giá trị này trong mảng phụ thuộc.

Ví dụ về giá trị phản ứng

javascript Copy
function ChatRoom({ roomId, selectedServerUrl }) { // roomId là phản ứng
    const settings = useContext(SettingsContext); // settings là phản ứng
    const serverUrl = selectedServerUrl ?? settings.defaultServerUrl; // serverUrl là phản ứng
    useEffect(() => {
      const connection = createConnection(serverUrl, roomId); // Effect của bạn đọc roomId và serverUrl
      connection.connect();
      return () => {
        connection.disconnect();
      };
    }, [roomId, serverUrl]); // Nó cần phải đồng bộ hóa lại khi bất kỳ giá trị nào trong số đó thay đổi!
}

Cảnh báo từ Linter

Khi một linter được cấu hình cho React, nó sẽ báo lỗi nếu một mảng phụ thuộc thiếu các giá trị. Linter không hoàn hảo và sẽ không tự động sửa lỗi, nhưng chúng ta nên đọc kỹ thông báo lỗi và sửa mã.

Tóm tắt

Tóm lại, chúng ta nên xem xét vòng đời của useEffect một cách riêng biệt so với vòng đời của các thành phần React. Hãy nghĩ về useEffect như là việc xử lý hai nhiệm vụ: bắt đầu đồng bộ hóa và dừng đồng bộ hóa. Ngoài ra, chúng ta nên tận dụng linter để phát hiện các vấn đề tiềm ẩn, đảm bảo rằng chúng ta không bỏ lỡ bất kỳ lỗi nào khi xây dựng ứng dụng của mình.

Thực hành tốt nhất

  • Tách biệt các tác động: Như đã đề cập, tách biệt các tác động trong useEffect giúp dễ dàng bảo trì và mở rộng mã.
  • Sử dụng mảng phụ thuộc chính xác: Luôn đảm bảo rằng bạn đã bao gồm tất cả các giá trị cần thiết trong mảng phụ thuộc của useEffect để tránh lỗi không mong muốn.

Những cạm bẫy phổ biến

  • Kết hợp nhiều tác động: Kết hợp nhiều tác động trong một useEffect có thể dẫn đến hành vi không mong muốn khi giá trị thay đổi.
  • Bỏ qua giá trị phản ứng: Bỏ qua các giá trị phản ứng trong mảng phụ thuộc có thể gây ra các lỗi khó phát hiện.

Mẹo hiệu suất

  • Tối ưu hóa các kết nối: Khi xây dựng các kết nối trong useEffect, hãy đảm bảo dọn dẹp đúng cách để tránh rò rỉ bộ nhớ.
  • Giảm thiểu số lần chạy Effect: Sử dụng mảng phụ thuộc để kiểm soát số lần chạy của Effect, giúp cải thiện hiệu suất.

Khắc phục sự cố

Nếu bạn gặp phải vấn đề với useEffect, hãy kiểm tra:

  • Các giá trị trong mảng phụ thuộc có được khai báo chính xác không.
  • Các hàm dọn dẹp có hoạt động đúng cách không.

Kết luận

useEffect là một công cụ mạnh mẽ trong React, giúp chúng ta quản lý các tác động phụ một cách hiệu quả. Hãy luôn chú ý đến cách bạn sử dụng useEffect để đảm bảo mã nguồn của bạn sạch sẽ và dễ bảo trì. Nếu bạn muốn tìm hiểu thêm về React và các kỹ thuật lập trình frontend, hãy theo dõi các bài viết tiếp theo của tôi!

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào