【翻译】在 React 中使用 react-error-boundary 进行错误处理

57 阅读6分钟

原文链接certificates.dev/blog/error-…

学习如何使用 react-error-boundary 在 React 应用中处理错误。探索 异常兜底UI、通过 useErrorBoundary 实现异步错误处理,以及 React 19 中表单操作和 useTransition 与自动错误边界集成的功能。

作者:Aurora Scharff

当 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>

该组件接收 errorresetErrorBoundary 作为 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>

该操作组件将函数封装在过渡中,捕获所有错误并显示带有重试选项的备用方案。可通过 useFormStatususeActionState 或单独的 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() 构建异步下拉框》一文。

源码: