mcpField
W
web-error-handling-error-boundaries

web-error-handling-error-boundaries

github.com/agents-inc开发2672 次安装2 天前更新
代码仓库

关于 web-error-handling-error-boundaries

面向 React 开发的错误边界技能,用于隔离渲染错误并提供备用界面与恢复路径。内容涵盖类边界、react-error-boundary、异步错误路由和 React 19 根级报告。

主要功能

  1. 01基于类的错误边界
  2. 02备用界面与重置控件
  3. 03通过 showBoundary() 传递异步错误
  4. 04细粒度边界布局
  5. 05React 19 根级错误报告

适用场景

  1. 01避免组件故障导致整页替换
  2. 02为渲染错误添加重试控件
  3. 03将异步故障传入备用界面
  4. 04集中报告 React 19 根级错误

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/agents-inc/skills --skill web-error-handling-error-boundaries

安装后在 Claude Code 中输入/web-error-handling-error-boundaries确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

metadata.yaml
reference.md
examples/
core.md
react-19-hooks.md
recovery.md
testing.md

详细介绍

React 错误边界

快速指南: 边界会捕获渲染期间、生命周期方法中以及构造函数中抛出的错误,并将子树替换为备用 UI。它无法捕获事件处理器、异步操作或服务端渲染中的错误——只有在有代码调用 showBoundary() 时,这些错误才会传递给它。边界必须是类组件,因为 getDerivedStateFromError 和 componentDidCatch 没有对应的 Hook。React 19 在 createRoot 中新增了 onCaughtError、onUncaughtError 和 onRecoverableError,用于记录错误,而非渲染 UI;React 18 会静默忽略这些选项。

详细资源:


适用路径

  • 不想引入边界依赖 — 自行编写类组件;getDerivedStateFromError 加上 componentDidCatch 就是完整 API,examples/core.md 中有完整示例。
  • 可使用 react-error-boundary — 直接使用 resetKeys、useErrorBoundary 和 FallbackProps 类型,而不是重新实现;请参阅 examples/core.md。
  • 使用 React 19,且关注的是记录日志而非 UI — 这三个 createRoot 选项会报告 所有错误,包括边界未能捕获的错误;请参阅 examples/react-19-hooks.md。

<critical_requirements>

编写错误边界代码前

从 getDerivedStateFromError 返回新状态,并将所有副作用放在 componentDidCatch 中。 前者在渲染期间运行,此时发起请求或调用日志函数会违反 React 的阶段规则;后者在提交阶段运行,此时执行这些操作是安全的。

除了根节点外,还要为每个功能区域分别添加边界。 单个根边界会让一个出错的小部件变成空白页面,而且只有将回退界面放在出错组件旁边,它才能说明具体哪里出了问题。

为回退界面提供恢复途径——重置回调、resetKeys,或两者兼备。 如果没有恢复途径,用户只能完整刷新页面,这会丢失他们输入的所有内容。

在回退界面上设置 role="alert",并使用真正的按钮作为控件。 否则子树消失时不会有任何提示,屏幕阅读器用户也无法得知发生了错误。

通过 showBoundary() 处理异步错误和事件处理程序中的错误。 边界无法捕获被拒绝的 Promise,因此未处理的 Promise 会让 UI 显示过时内容,且完全没有错误状态。

</critical_requirements>


自动检测: error boundary、ErrorBoundary、getDerivedStateFromError、componentDidCatch、fallback UI、react-error-boundary、useErrorBoundary、showBoundary、error fallback、onCaughtError、onUncaughtError、onRecoverableError、captureOwnerStack、FallbackProps、resetKeys

适用范围:

  • 捕获渲染阶段的错误,并显示回退 UI 替代出错内容
  • 捕获错误后的重置与重试,包括重试次数限制和退避策略
  • 决定边界的放置位置,以及每个边界的覆盖范围
  • 从 React 根节点集中报告错误

其他内容:

  • 服务端渲染中抛出的错误——渲染框架决定渲染失败时向客户端发送什么,而此时客户端边界尚未挂载。
  • 数据层中的请求失败——只有在某处重新抛出错误或调用 showBoundary() 时,边界才能看到它;重试和缓存失效由发起请求的部分负责。
  • 字段级验证反馈——无效的表单字段属于预期输入,因此应以内联方式渲染,而不是替换整个子树。
  • 监控目标——onError 和根节点处理程序会将错误和组件堆栈交给你,如何处理这些信息属于报告工具的职责。

理念

如果没有边界捕获渲染错误,整个树都会卸载:React 会拆除根节点,而不是让屏幕上保留只渲染了一半的文档,因此任何位置抛出的一个错误都会变成空白页面。

边界能提供隔离:影响范围是最近边界包裹的子树,因此边界的位置决定了单个错误会让页面损失多少内容。这使边界的放置成为真正需要考虑的决策——恢复方式、回退提示文案和日志记录都由此而定。

边界不能替代 try/catch;它们负责覆盖 try/catch 无法触及的区域,也就是 React 自身的渲染过程。


核心模式

模式 1:基于类的边界

这两个生命周期方法按阶段分工:getDerivedStateFromError 是纯函数,只返回状态;报告错误则放在 componentDidCatch 中。

static getDerivedStateFromError(error: Error): State {
  return { hasError: true, error };
}

componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
  this.props.onError?.(error, errorInfo);
}

完整代码:examples/core.md

模式 2:react-error-boundary

FallbackComponent 会接收 error 和 resetErrorBoundary,因此可以根据设计需要将重试控件放在任意位置。onError 则将错误报告逻辑与回退界面分开。

<ErrorBoundary FallbackComponent={ErrorFallback} onError={report}>
  <Dashboard />
</ErrorBoundary>;

function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
  return (
    <div role="alert">
      <p>{error.message}</p>
      <button onClick={resetErrorBoundary}>Try again</button>
    </div>
  );
}

属性表见 reference.md;完整代码见 examples/core.md。

模式 3:使用 showBoundary() 处理异步错误

异步操作中抛出的错误不会自行传递到边界。useErrorBoundary 会提供触发函数。

const { showBoundary } = useErrorBoundary();

const load = async () => {
  try {
    const response = await fetch(endpoint);
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
  } catch (error) {
    showBoundary(error);
  }
};

如果错误发生时需要替换整个子树,就在相应位置使用它。如果错误有自己的内联 UI(例如字段级验证消息),则不要使用它。

完整代码:examples/core.md

模式 4:用于自动重置的 resetKeys

任何列出的值发生变化,都会清除错误并重新渲染子组件,这正是导航和切换记录所需要的行为。

<ErrorBoundary FallbackComponent={ErrorFallback} resetKeys={[currentPath]}>
  <PageContent path={currentPath} />
</ErrorBoundary>

比较是浅层的,因此对象或数组形式的键需要保持引用稳定,否则边界会在每次渲染时重置。

模式 5:精细放置

每个组件都有自己的边界和回退文本;根边界则捕获内部边界未捕获的错误。

<ErrorBoundary fallback={<p>Chart unavailable</p>} onError={report}>
  <ChartWidget />
</ErrorBoundary>
<ErrorBoundary fallback={<p>Table unavailable</p>} onError={report}>
  <DataTable />
</ErrorBoundary>

用一个边界包裹全部三个组件,会导致第一个错误发生时,另外两个也随之消失。

边界有一个上限:其单元应是用户能够识别为独立故障的功能区域。每个组件都设置边界,会增加用户根本不会看的类组件和回退文本,还会把一个故障拆成一页小型损坏面板,而不是显示一条直白的信息。

完整代码:examples/core.md

模式 6:回退 UI

回退 UI 是用户在最糟糕时刻看到的界面:告知用户发生了什么,提供脱困方式,并将堆栈跟踪保留给开发环境。

<div role="alert">
  <h2>Something went wrong</h2>
  {isDevelopment && <pre>{error.message}</pre>}
  <button onClick={resetErrorBoundary}>Try again</button>
</div>

<span onClick> 重试操作无法通过键盘触发,而在生产环境中显示原始堆栈则会泄露内部信息。

完整代码:examples/core.md

模式 7:React 19 根错误选项

createRoot 提供三个处理程序,用于报告错误而非渲染错误,包括未被任何边界捕获的错误。它们与边界互为补充,而不是用来替代边界。

const root = createRoot(container, {
  onCaughtError: (error, info) => report("caught", error, info.componentStack),
  onUncaughtError: (error, info) =>
    report("uncaught", error, info.componentStack),
  onRecoverableError: (error, info) =>
    report("recoverable", error, info.componentStack),
});

完整代码:examples/react-19-hooks.md


<red_flags>

注意事项

运行时会出错:

  • 在 getDerivedStateFromError 中执行副作用——它在渲染期间运行,因此在其中发起请求或调用 setState 会违反 React 的阶段规则;应改为在 componentDidCatch 中报告。
  • 边界包裹自身——边界无法捕获自身渲染错误,抛出的错误会传递给父边界或根节点;应让回退 UI 保持简单。
  • 不稳定的 resetKeys 条目——浅层比较会发现每次渲染都产生了新的数组或对象,并持续重置边界;请对该值使用 memo,或将键设为原始类型。
  • 使用 <span onClick={reset}> 作为重试控件——无法获得焦点,也无法通过 Enter 或 Space 激活;请使用 <button>。

行为可能出乎意料:

  • 异步错误和事件处理程序中的错误永远不会传递给边界;如果没有 showBoundary(),它们就会消失。
  • 最内层边界优先,因此只有所有内层边界都未捕获错误时,才会显示范围较大的根回退 UI。
  • SSR 水合错误会作为可恢复错误而非已捕获错误出现,客户端边界可能永远看不到它们。
  • 开发环境热重载可能触发生产环境中不会出现的边界。
  • onCaughtError 在边界自身的 componentDidCatch 之后运行,而不是之前。
  • onRecoverableError 中的 error.cause 通常包含原始错误。
  • 在开发环境之外,captureOwnerStack() 会返回 null。
  • 在 React 18 中,三个根选项会被静默忽略——既不会警告,也不会报错或记录日志。

</red_flags>

评论

支持 Markdown