原文链接certificates.dev/blog/error-…
学习如何使用 react-error-boundary 在 React 应用中处理错误。探索 异常兜底UI、通过 useErrorBoundary 实现异步错误处理,以及 React 19 中表单操作和 useTransition 与自动错误边界集成的功能。
当 React 组件在渲染过程中抛出错误时,会导致整个应用程序崩溃,用户界面将显示为空白。react-error-boundary 库通过捕获错误并显示异常兜底界面来解决此问题。
本文将探讨如何在 React 中使用 react-error-boundary 进行错误处理。我们将涵盖三种渲染异常兜底界面的方式、在路由和功能层面的策略性部署,以及通过抛出异常、useErrorBoundary 钩子和 React 19 自动错误边界与动作(Actions)的集成来处理异步错误。
开始
首先,从 npm 安装 react-error-boundary 库:
npm install react-error-boundary
安装完成后,导入 ErrorBoundary 组件,并将其包裹在组件树中需要捕获错误的任意部分。
实现异常兜底方案的三种方式
ErrorBoundary 组件支持三种不同的备用 UI 接收方式,可根据需求灵活选择。
简单异常兜底组件
使用错误边界最简单的方式是采用静态备用元素。当您需要显示基本错误消息却无法获取错误详情或恢复选项时,请使用此方法:
import { ErrorBoundary } from "react-error-boundary";
<ErrorBoundary fallback={<div>Something went wrong</div>}>
<MyComponent />
</ErrorBoundary>
备用元素不会接收任何 props——它只是在发生错误时显示的静态 React 元素。
异常兜底组件
当您需要访问错误详情和重置功能时,请将组件传递给 FallbackComponent 属性:
function ErrorFallback({ error, resetErrorBoundary }) {
return (
<div role="alert">
<h2>Something went wrong</h2>
<pre>{error.message}</pre>
<button onClick={resetErrorBoundary}>Try again</button>
</div>
);
}
<ErrorBoundary FallbackComponent={ErrorFallback}>
<MyComponent />
</ErrorBoundary>
该组件接收 error 和 resetErrorBoundary 作为 props,允许您显示特定错误消息并提供恢复选项。
渲染属性模式
fallbackRender 属性在功能上与 FallbackComponent 完全相同,但采用渲染属性模式而非独立组件:
<ErrorBoundary
fallbackRender={({ error, resetErrorBoundary }) => (
<div role="alert">
<p>Error: {error.message}</p>
<button onClick={resetErrorBoundary}>Retry</button>
</div>
)}
>
<MyComponent />
</ErrorBoundary>
使用 fallbackRender 实现内联错误 UI,当需要跨多个边界复用错误组件时则使用 FallbackComponent。
错误边界可与 Suspense 等 React 特性组合使用,助您构建声明式 UI——在边界层级处理加载和错误状态,而非在单个组件内部处理。这使组件逻辑专注于正常流程,而边界负责处理边界情况。
错误记录
除了向用户显示错误信息外,你还需要追踪这些错误以便调试。onError 回调函数可将错误发送至监控服务或记录至后端系统:
const logError = (error, info) => {
console.error("Caught error:", error);
console.error("Component stack:", info.componentStack);
// Send to error tracking service
};
<ErrorBoundary FallbackComponent={ErrorFallback} onError={logError}>
<MyComponent />
</ErrorBoundary>
回调函数会接收错误信息和组件堆栈跟踪,您可以将其发送至Sentry或LogRocket等监控服务。
战略性误差边界设置
错误边界的设置决定了系统故障时UI不可用范围的大小。避免将每个组件都包裹起来——这会导致错误信息散乱,造成视觉混乱。相反,应在逻辑分界处设置边界,例如路由或功能模块,这样既能隔离错误,又不会破坏整体用户体验。
路由级边界
在路由层设置错误边界,确保页面崩溃时导航功能仍可正常使用:
<Layout>
<Header />
<ErrorBoundary FallbackComponent={PageError}>
<Route />
</ErrorBoundary>
<Footer />
</Layout>
即使路由抛出错误,页眉、页脚和导航功能仍可正常使用。
功能级边界
将独立功能封装在独立边界中以隔离故障:
<Dashboard>
<ErrorBoundary fallback={<WidgetError />}>
<AnalyticsWidget />
</ErrorBoundary>
<ErrorBoundary fallback={<WidgetError />}>
<NotificationsWidget />
</ErrorBoundary>
</Dashboard>
如果分析小部件发生崩溃,通知功能仍将独立运行。
处理异步错误
错误边界会在渲染过程中捕获错误,但不会捕获来自事件处理程序、异步回调或 Promise 的错误。这意味着您需要采用不同的方法来处理异步操作。
抛出错误
最简单的方法是在渲染过程中抛出错误。如果你的钩子函数返回错误,请将其抛出以传播至最近的错误边界:
function UserProfile() {
const { status, data, error } = useUser();
if (error) throw error;
return status === 'success' ? <div>{data.name}</div> : <div>Loading...</div>; }
这消除了对try-catch代码块或局部错误状态的需求。诸如TanStack Query之类的数据获取库也能通过 throwOnError 等选项自动提供此功能。
使用 useErrorBoundary 钩子
当无法在渲染过程中抛出异常(例如在事件处理程序或异步回调中)时,可使用 useErrorBoundary 钩子手动传播错误:
import { useErrorBoundary } from "react-error-boundary";
function MyComponent() {
const { showBoundary } = useErrorBoundary();
const handleSubmit = async () => {
try { await submitForm(); }
catch (error) { showBoundary(error); }
};
return <button onClick={handleSubmit}>Submit</button>;
}
showBoundary 函数将错误传播至最近的错误边界,如同渲染错误般触发备用界面。
使用Actions
或者,React 19 动作提供了自动错误边界集成,无需手动处理错误。动作是在转换内部调用的函数——它们可以在后台执行工作时更新状态并产生副作用,同时不会阻塞用户交互。React 会自动捕获动作抛出的任何错误,并将其传播到最近的错误边界。
要深入了解 React 19 动作,请参阅《使用 React 19 动作构建可复用组件》。
表单Actions
使用 Actions 的最简单方式是通过 React 19 的表单 action 属性,或任何提供 action 属性的其他库:
function SubmitForm() {
async function submitAction(formData) {
await submitFormData(formData.get('email'));
}
return (
<form action={submitAction}>
<input name="email" required />
<button type="submit">
Submit
</button>
</form>
);
}
function FormError({ error, resetErrorBoundary }) {
return (
<div role="alert">
<p>{error.message}</p>
<button onClick={resetErrorBoundary}>Try again</button>
</div>
);
}
<ErrorBoundary FallbackComponent={FormError}>
<SubmitForm />
</ErrorBoundary>
该操作组件将函数封装在过渡中,捕获所有错误并显示带有重试选项的备用方案。可通过 useFormStatus、useActionState 或单独的 useTransition 组件追踪待处理状态。
useTransition Actions
对于非表单的异步代码,请使用 useTransition 钩子:
import { useTransition } from "react";
function DeleteButton({ itemId }) {
const [isPending, startTransition] = useTransition();
const handleDelete = () => {
startTransition(async () => {
await deleteItem(itemId);
});
};
return (
<button onClick={handleDelete} disabled={isPending}>
{isPending ? "Deleting..." : "Delete"}
</button>
);
}
这与上述表单操作示例完全相同——错误会被最近的错误边界自动捕获。
结论
react-error-boundary 库为 React 提供了声明式的错误处理方案。ErrorBoundary 组件可捕获渲染错误,并为静态元素、组件或渲染属性提供灵活的回退 UI 选项。对于异步操作,您可在渲染时抛出错误,使用 useErrorBoundary 钩子处理事件,或借助 React 19 对表单操作和 useTransition 的自动错误边界集成。
在路由和功能层面的战略性部署,确保错误发生时界面仍保持可用,避免分散的错误提示造成视觉混乱。结合错误日志记录、重置功能以及 React 19 内置的过渡支持,错误边界能构建出优雅处理故障的弹性应用。
欲了解实际应用场景,请参阅《使用 useSuspenseQuery() 和 useDeferredValue() 构建异步下拉框》一文。
源码: