Giới Thiệu: Lỗi Là Điều Không Thể Tránh (Đừng Lo!)
Ngay cả những lập trình viên dày dạn kinh nghiệm cũng đôi khi mắc phải sai sót. Trong thế giới React, lỗi trong các thành phần có thể dẫn đến ứng dụng bị sập và tạo ra trải nghiệm người dùng tồi tệ. Tuy nhiên, đừng lo lắng! React cung cấp một công cụ mạnh mẽ gọi là Error Boundaries để bắt lỗi, ngăn chặn sự cố và hiển thị giao diện dự phòng thay vì màn hình bị treo. Bài viết này sẽ hướng dẫn bạn tất cả những gì bạn cần biết về Error Boundaries, với các giải thích rõ ràng, ví dụ mã TypeScript hữu ích, các nghiên cứu trường hợp thực tế và giới thiệu thư viện react-error-boundary
.
Error Boundaries Là Gì? Lưới An Toàn Của Ứng Dụng Của Bạn
Error boundaries là các thành phần React có khả năng bắt các 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 dự phòng thay vì cây thành phần bị sập. Chúng giống như một lưới an toàn cho ứng dụng của bạn, ngăn không cho một lỗi đơn lẻ làm hỏng toàn bộ hệ thống.
Cách Error Boundaries Hoạt Động: Bắt Lỗi Như Một Chuyên Gia
Error boundaries hoạt động bằng cách triển khai một hoặc cả hai phương thức vòng đời sau:
static getDerivedStateFromError(error)
: Phương thức này được gọi sau khi một lỗi được ném ra từ một thành phần con. Nó nhận lỗi như một tham số và nên trả về một đối tượng để cập nhật state, thường là để hiển thị giao diện dự phòng.componentDidCatch(error, errorInfo)
: Phương thức này được gọi sau khi một lỗi được ném ra từ một thành phần con. Nó nhận hai tham số: lỗi và thông tin về lỗi (bao gồm thông tin về stack trace). Phương thức này thường được sử dụng để ghi lại lỗi vào dịch vụ theo dõi lỗi.
Lưu Ý Quan Trọng: Error boundaries chỉ bắt lỗi trong các thành phần bên dưới chúng trong cây component. Chúng không bắt lỗi trong:
- Chính Error boundary.
- Các handler sự kiện.
- Mã bất đồng bộ (ví dụ, các callback từ
setTimeout
hoặcrequestAnimationFrame
). - Server-side rendering.
Tạo Error Boundary: Ví Dụ Với TypeScript
Dưới đây là hướng dẫn từng bước để tạo một Error Boundary trong TypeScript.
import React, { Component, ReactNode } from "react";
interface ErrorBoundaryState {
hasError: boolean;
error?: Error;
errorInfo?: React.ErrorInfo;
}
class ErrorBoundary extends Component<{}, ErrorBoundaryState> {
constructor(props: {}) {
super(props);
this.state = { hasError: false, error: undefined, errorInfo: undefined };
}
static getDerivedStateFromError(error: Error) {
// Cập nhật state để render lại và hiển thị giao diện dự phòng
return { hasError: true };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
// Ghi lại lỗi vào dịch vụ báo cáo lỗi
console.error("Caught an error:", error, errorInfo);
// Bạn có thể ghi lại lỗi vào dịch vụ theo dõi lỗi yêu thích của mình, ví dụ: Sentry, LogRocket
this.setState({ error, errorInfo });
}
render() {
if (this.state.hasError) {
// Bạn có thể render bất kỳ giao diện dự phòng tùy chỉnh nào
return (
<div>
<h1>Đã có sự cố xảy ra.</h1>
<p>Chúng tôi đang khắc phục sự cố. Vui lòng thử lại sau.</p>
<details style={{ whiteSpace: "pre-wrap" }}>
<summary>Chi tiết lỗi</summary>
{this.state.error?.message}
<br />
{this.state.errorInfo?.componentStack}
</details>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
Sử Dụng Error Boundary: Bảo Vệ Các Thành Phần Của Bạn
Quấn các thành phần bạn muốn bảo vệ trong ErrorBoundary component:
import React from "react";
import ErrorBoundary from "./ErrorBoundary";
import MyComponent from "./MyComponent"; // Đây có thể là một thành phần dễ gặp lỗi
function App() {
return (
<div>
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
{/* Các thành phần khác bên ngoài ErrorBoundary sẽ không bị ảnh hưởng bởi lỗi trong MyComponent */}
</div>
);
}
Nghiên Cứu Trường Hợp: Ví Dụ Thực Tế
Trang Sản Phẩm Thương Mại Điện Tử
Giả sử trang sản phẩm gặp sự cố do lỗi khi lấy dữ liệu sản phẩm. Một Error Boundary có thể bắt lỗi này và hiển thị một thông báo thân thiện với người dùng như “Rất tiếc! Có sự cố xảy ra. Chúng tôi đang khắc phục,” kèm theo nút thử lại. Điều này giúp tránh màn hình trắng và cung cấp trải nghiệm người dùng tốt hơn.
Dòng Thời Gian Mạng Xã Hội
Nếu xảy ra lỗi trong khi render một bài đăng trên dòng thời gian mạng xã hội, Error Boundary có thể bắt lỗi và ngăn chặn toàn bộ dòng thời gian bị sập. Nó có thể hiển thị một placeholder cho bài đăng gặp sự cố, cho phép người dùng tiếp tục duyệt dòng thời gian.
Dashboard Tương Tác Dữ Liệu
Trong một dashboard phân tích dữ liệu phức tạp, lỗi trong một biểu đồ không nên khiến toàn bộ dashboard sập. Error Boundary có thể cô lập biểu đồ gặp lỗi và hiển thị thông báo lỗi, đảm bảo các biểu đồ khác vẫn hoạt động bình thường.
Các Thực Hành Tốt Nhất: Kinh Nghiệm Với Error Boundaries
- Sử dụng nhiều Error Boundaries: Quấn các phần khác nhau của ứng dụng trong các Error Boundaries riêng biệt để cô lập lỗi và ngăn ngừa sự cố lan rộng. Đừng chỉ đặt một cái ở root của ứng dụng!
- Cung cấp phản hồi thông tin: Đừng chỉ nói “Có gì đó sai.” Cung cấp thông báo lỗi cụ thể (khi thích hợp) và hướng dẫn người dùng có thể làm gì (ví dụ: tải lại trang, liên hệ hỗ trợ).
- Ghi lại lỗi: Sử dụng
componentDidCatch
để ghi lại chi tiết lỗi vào dịch vụ như Sentry hoặc LogRocket. Điều này giúp bạn theo dõi và khắc phục lỗi hiệu quả hơn. - Không lạm dụng Error Boundaries: Error boundaries không thay thế việc xử lý lỗi đúng cách và lập trình phòng ngừa. Sử dụng chúng một cách chiến lược để xử lý lỗi bất ngờ và ngăn chặn sự cố.
- Xem xét trải nghiệm người dùng: Giao diện dự phòng của bạn nên thân thiện và cung cấp thông tin hữu ích. Một giao diện dự phòng được thiết kế tốt có thể biến một trải nghiệm khó chịu thành một trải nghiệm tích cực.
Giới Thiệu Thư Viện react-error-boundary
Thư viện react-error-boundary
đơn giản hóa quá trình thêm Error Boundaries vào các ứng dụng React của bạn. Nó cung cấp một component wrapper tiện lợi và các tính năng bổ sung giúp xử lý lỗi một cách duyên dáng.
Cài Đặt react-error-boundary
Bạn có thể cài đặt thư viện react-error-boundary
bằng npm hoặc yarn:
npm install react-error-boundary
hoặc
yarn add react-error-boundary
Sử Dụng react-error-boundary
Trong TypeScript
Dưới đây là cách sử dụng thư viện react-error-boundary
trong dự án TypeScript:
import React from "react";
import { ErrorBoundary } from "react-error-boundary";
import MyComponent from "./MyComponent"; // Đây có thể là một thành phần dễ gặp lỗi
function FallbackComponent({
error,
resetErrorBoundary,
}: {
error: Error;
resetErrorBoundary: () => void;
}) {
return (
<div>
<h1>Rất tiếc, có lỗi xảy ra!</h1>
<p>{error.message}</p>
<button onClick={resetErrorBoundary}>Thử lại</button>
</div>
);
}
function App() {
return (
<div>
<ErrorBoundary
FallbackComponent={FallbackComponent}
onReset={() => {
// Reset lại trạng thái ứng dụng của bạn ở đây
}}
>
<MyComponent />
</ErrorBoundary>
{/* Các thành phần khác bên ngoài ErrorBoundary sẽ không bị ảnh hưởng bởi lỗi trong MyComponent */}
</div>
);
}
export default App;
Các Tính Năng Chính Của react-error-boundary
FallbackComponent
: Cho phép bạn chỉ định một component để render khi có lỗi xảy ra.onReset
: Hàm callback được gọi khi người dùng cố gắng reset lại trạng thái ứng dụng sau một lỗi.FallbackRender
: Prop render thay thế choFallbackComponent
.
Ví Dụ Với FallbackRender
import React from "react";
import { ErrorBoundary } from "react-error-boundary";
import MyComponent from "./MyComponent"; // Đây có thể là một thành phần dễ gặp lỗi
function App() {
return (
<div>
<ErrorBoundary
fallbackRender={({ error, resetErrorBoundary }) => (
<div>
<h1>Rất tiếc, có lỗi xảy ra!</h1>
<p>{error.message}</p>
<button onClick={resetErrorBoundary}>Thử lại</button>
</div>
)}
onReset={() => {
// Reset lại trạng thái ứng dụng của bạn ở đây
}}
>
<MyComponent />
</ErrorBoundary>
{/* Các thành phần khác bên ngoài ErrorBoundary sẽ không bị ảnh hưởng bởi lỗi trong MyComponent */}
</div>
);
}
export default App;
Kết Luận: Hãy Chấp Nhận Lỗi (Và Xử Lý Chúng Một Cách Duyên Dáng)
Lỗi là điều không thể tránh khỏi trong phát triển phần mềm. Nhưng với React Error Boundaries, bạn có thể xử lý chúng một cách duyên dáng, ngăn chặn sự cố và cung cấp một trải nghiệm người dùng tốt hơn. Hãy sử dụng công cụ mạnh mẽ này một cách hợp lý và ứng dụng React của bạn sẽ trở nên mạnh mẽ, đáng tin cậy và thân thiện với người dùng hơn. Không còn nước mắt (ít nhất là không phải vì ứng dụng bị sập 🙂)!