Tiếng Việt

Học cách triển khai Ranh giới Lỗi React để xử lý lỗi hiệu quả, ngăn ứng dụng sập và cải thiện trải nghiệm người dùng. Khám phá các phương pháp hay nhất, kỹ thuật nâng cao và ví dụ thực tế.

Ranh giới Lỗi React: Hướng dẫn Toàn diện về Xử lý Lỗi Mạnh mẽ

Trong thế giới phát triển web hiện đại, trải nghiệm người dùng mượt mà và đáng tin cậy là tối quan trọng. Một lỗi không được xử lý duy nhất có thể làm sập toàn bộ ứng dụng React, khiến người dùng thất vọng và có khả năng mất dữ liệu quý giá. Ranh giới Lỗi (Error Boundaries) của React cung cấp một cơ chế mạnh mẽ để xử lý các lỗi này một cách duyên dáng, ngăn chặn các sự cố thảm khốc và mang lại trải nghiệm linh hoạt và thân thiện hơn với người dùng. Hướng dẫn này cung cấp một cái nhìn tổng quan toàn diện về Ranh giới Lỗi React, bao gồm mục đích, cách triển khai, các phương pháp hay nhất và các kỹ thuật nâng cao.

Ranh giới Lỗi React là gì?

Ranh giới Lỗi là các thành phần React bắt lỗi JavaScript ở bất kỳ đâu trong cây thành phần con của chúng, ghi lại các lỗi đó và hiển thị một giao diện người dùng dự phòng (fallback UI) thay vì cây thành phần đã bị sập. Chúng hoạt động như một lưới an toàn, ngăn chặn các lỗi ở một phần của ứng dụng làm sập toàn bộ giao diện người dùng. Được giới thiệu trong React 16, Ranh giới Lỗi đã thay thế các cơ chế xử lý lỗi trước đây, kém mạnh mẽ hơn.

Hãy coi Ranh giới Lỗi như các khối lệnh `try...catch` cho các thành phần React. Tuy nhiên, không giống như `try...catch`, chúng hoạt động cho các thành phần, cung cấp một cách khai báo và tái sử dụng để xử lý lỗi trên toàn ứng dụng của bạn.

Tại sao nên sử dụng Ranh giới Lỗi?

Ranh giới Lỗi mang lại một số lợi ích quan trọng:

Tạo một Thành phần Ranh giới Lỗi

Để tạo một thành phần Ranh giới Lỗi, bạn cần định nghĩa một class component triển khai một hoặc cả hai phương thức vòng đời sau:

Đây là một ví dụ cơ bản về một thành phần Ranh giới Lỗi:


class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Cập nhật state để lần render tiếp theo sẽ hiển thị UI dự phòng.
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // Ví dụ "componentStack":
    //   in ComponentThatThrows (created by App)
    //   in App
    console.error("Đã bắt được một lỗi: ", error, info.componentStack);
    // Bạn cũng có thể ghi lại lỗi vào một dịch vụ báo cáo lỗi
    // logErrorToMyService(error, info.componentStack);
  }

  render() {
    if (this.state.hasError) {
      // Bạn có thể render bất kỳ UI dự phòng tùy chỉnh nào
      return 

Đã có lỗi xảy ra.

; } return this.props.children; } }

Giải thích:

Sử dụng Ranh giới Lỗi

Để sử dụng Ranh giới Lỗi, chỉ cần bọc thành phần hoặc các thành phần bạn muốn bảo vệ bằng thành phần ErrorBoundary:



  


Nếu ComponentThatMightThrow ném ra một lỗi, ErrorBoundary sẽ bắt lỗi đó, cập nhật state của nó và render giao diện người dùng dự phòng của nó. Phần còn lại của ứng dụng sẽ tiếp tục hoạt động bình thường.

Vị trí đặt Ranh giới Lỗi

Việc đặt Ranh giới Lỗi là rất quan trọng để xử lý lỗi hiệu quả. Hãy xem xét các chiến lược sau:

Ví dụ:


function App() {
  return (
    
); }

Trong ví dụ này, mỗi phần chính của ứng dụng (Header, Sidebar, ContentArea, Footer) được bọc bằng một Ranh giới Lỗi. Điều này cho phép mỗi phần xử lý lỗi một cách độc lập, ngăn chặn một lỗi duy nhất ảnh hưởng đến toàn bộ ứng dụng.

Tùy chỉnh Giao diện người dùng Dự phòng

Giao diện người dùng dự phòng được hiển thị bởi Ranh giới Lỗi nên có tính thông tin và thân thiện với người dùng. Hãy xem xét các hướng dẫn sau:

Ví dụ:


class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Cập nhật state để lần render tiếp theo sẽ hiển thị UI dự phòng.
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // Bạn cũng có thể ghi lại lỗi vào một dịch vụ báo cáo lỗi
    console.error("Đã bắt được một lỗi: ", error, info.componentStack);
  }

  render() {
    if (this.state.hasError) {
      // Bạn có thể render bất kỳ UI dự phòng tùy chỉnh nào
      return (
        

Ôi! Đã có lỗi xảy ra.

Chúng tôi xin lỗi, nhưng đã có lỗi xảy ra khi cố gắng hiển thị nội dung này.

Vui lòng thử làm mới trang hoặc liên hệ với bộ phận hỗ trợ nếu sự cố vẫn tiếp diễn.

Liên hệ Hỗ trợ
); } return this.props.children; } }

Ví dụ này hiển thị một giao diện người dùng dự phòng có nhiều thông tin hơn bao gồm một thông báo lỗi rõ ràng, các giải pháp được đề xuất và các liên kết để làm mới trang và liên hệ với bộ phận hỗ trợ.

Xử lý các loại Lỗi khác nhau

Ranh giới Lỗi bắt các lỗi xảy ra trong quá trình render, trong các phương thức vòng đời và trong hàm khởi tạo của toàn bộ cây bên dưới chúng. Chúng *không* bắt lỗi cho:

Để xử lý các loại lỗi này, bạn cần sử dụng các kỹ thuật khác nhau.

Trình xử lý sự kiện

Đối với các lỗi xảy ra trong trình xử lý sự kiện, hãy sử dụng một khối lệnh try...catch tiêu chuẩn:


function MyComponent() {
  const handleClick = () => {
    try {
      // Mã có thể ném ra lỗi
      throw new Error("Đã có lỗi xảy ra trong trình xử lý sự kiện");
    } catch (error) {
      console.error("Lỗi trong trình xử lý sự kiện: ", error);
      // Xử lý lỗi (ví dụ: hiển thị thông báo lỗi)
      alert("Đã có lỗi xảy ra. Vui lòng thử lại.");
    }
  };

  return ;
}

Mã bất đồng bộ

Đối với các lỗi xảy ra trong mã bất đồng bộ, hãy sử dụng các khối lệnh try...catch bên trong hàm bất đồng bộ:


function MyComponent() {
  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch("https://api.example.com/data");
        const data = await response.json();
        // Xử lý dữ liệu
        console.log(data);
      } catch (error) {
        console.error("Lỗi khi tìm nạp dữ liệu: ", error);
        // Xử lý lỗi (ví dụ: hiển thị thông báo lỗi)
        alert("Không thể tìm nạp dữ liệu. Vui lòng thử lại sau.");
      }
    }

    fetchData();
  }, []);

  return 
Đang tải dữ liệu...
; }

Ngoài ra, bạn có thể sử dụng một cơ chế xử lý lỗi toàn cục cho các promise rejection không được xử lý:


window.addEventListener('unhandledrejection', function(event) {
  console.error('Promise rejection không được xử lý (promise: ', event.promise, ', lý do: ', event.reason, ');');
  // Tùy chọn hiển thị một thông báo lỗi toàn cục hoặc ghi lại lỗi vào một dịch vụ
  alert("Đã xảy ra một lỗi không mong muốn. Vui lòng thử lại sau.");
});

Các kỹ thuật Ranh giới Lỗi nâng cao

Đặt lại Ranh giới Lỗi

Trong một số trường hợp, bạn có thể muốn cung cấp một cách để người dùng đặt lại Ranh giới Lỗi và thử lại thao tác đã gây ra lỗi. Điều này có thể hữu ích nếu lỗi được gây ra bởi một sự cố tạm thời, chẳng hạn như sự cố mạng.

Để đặt lại Ranh giới Lỗi, bạn có thể sử dụng một thư viện quản lý trạng thái như Redux hoặc Context để quản lý trạng thái lỗi và cung cấp một hàm đặt lại. Ngoài ra, bạn có thể sử dụng một cách tiếp cận đơn giản hơn bằng cách buộc Ranh giới Lỗi phải được gắn kết lại (remount).

Ví dụ (Buộc gắn kết lại):


class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, errorCount: 0, key: 0 };
  }

  static getDerivedStateFromError(error) {
    // Cập nhật state để lần render tiếp theo sẽ hiển thị UI dự phòng.
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // Bạn cũng có thể ghi lại lỗi vào một dịch vụ báo cáo lỗi
    console.error("Đã bắt được một lỗi: ", error, info.componentStack);
    this.setState(prevState => ({ errorCount: prevState.errorCount + 1 }));
  }

  resetError = () => {
      this.setState({hasError: false, key: this.state.key + 1})
  }

  render() {
    if (this.state.hasError) {
      // Bạn có thể render bất kỳ UI dự phòng tùy chỉnh nào
      return (
        

Ôi! Đã có lỗi xảy ra.

Chúng tôi xin lỗi, nhưng đã có lỗi xảy ra khi cố gắng hiển thị nội dung này.

); } return
{this.props.children}
; } }

Trong ví dụ này, một 'key' được thêm vào div bao bọc. Việc thay đổi key sẽ buộc thành phần phải được gắn kết lại, giúp xóa trạng thái lỗi một cách hiệu quả. Phương thức `resetError` cập nhật state `key` của thành phần, khiến thành phần được gắn kết lại và render lại các con của nó.

Sử dụng Ranh giới Lỗi với Suspense

React Suspense cho phép bạn "tạm dừng" việc render một thành phần cho đến khi một điều kiện nào đó được đáp ứng (ví dụ: dữ liệu được tìm nạp). Bạn có thể kết hợp Ranh giới Lỗi với Suspense để cung cấp một trải nghiệm xử lý lỗi mạnh mẽ hơn cho các hoạt động bất đồng bộ.


import React, { Suspense } from 'react';

function MyComponent() {
  return (
    
      Đang tải...
}> ); } function DataFetchingComponent() { const data = useData(); // Hook tùy chỉnh tìm nạp dữ liệu bất đồng bộ return
{data.value}
; }

Trong ví dụ này, DataFetchingComponent tìm nạp dữ liệu một cách bất đồng bộ bằng một hook tùy chỉnh. Thành phần Suspense hiển thị một chỉ báo tải trong khi dữ liệu đang được tìm nạp. Nếu có lỗi xảy ra trong quá trình tìm nạp dữ liệu, ErrorBoundary sẽ bắt lỗi và hiển thị một giao diện người dùng dự phòng.

Các phương pháp hay nhất cho Ranh giới Lỗi React

Ví dụ trong thế giới thực

Dưới đây là một vài ví dụ thực tế về cách có thể sử dụng Ranh giới Lỗi:

Các giải pháp thay thế cho Ranh giới Lỗi

Mặc dù Ranh giới Lỗi là cách được khuyến nghị để xử lý lỗi trong React, có một số cách tiếp cận thay thế bạn có thể xem xét. Tuy nhiên, hãy nhớ rằng những giải pháp thay thế này có thể không hiệu quả bằng Ranh giới Lỗi trong việc ngăn chặn sự cố ứng dụng và cung cấp trải nghiệm người dùng liền mạch.

Cuối cùng, Ranh giới Lỗi cung cấp một cách tiếp cận mạnh mẽ và được tiêu chuẩn hóa để xử lý lỗi trong React, khiến chúng trở thành lựa chọn ưu tiên cho hầu hết các trường hợp sử dụng.

Kết luận

Ranh giới Lỗi React là một công cụ thiết yếu để xây dựng các ứng dụng React mạnh mẽ và thân thiện với người dùng. Bằng cách bắt lỗi và hiển thị giao diện người dùng dự phòng, chúng ngăn chặn sự cố ứng dụng, cải thiện trải nghiệm người dùng và đơn giản hóa việc gỡ lỗi. Bằng cách tuân theo các phương pháp hay nhất được nêu trong hướng dẫn này, bạn có thể triển khai Ranh giới Lỗi một cách hiệu quả trong các ứng dụng của mình và tạo ra một trải nghiệm người dùng linh hoạt và đáng tin cậy hơn cho người dùng trên toàn cầu.