错误边界
本页内容

错误边界



为了避免向用户呈现空白页面,路由模块会自动捕获代码中的错误并呈现最近的 ErrorBoundary

错误边界不适用于错误报告或呈现表单验证错误。请参阅表单验证错误报告

1. 添加根错误边界

所有应用程序至少应导出一个根错误边界。这个边界处理三种主要情况:

  • 抛出的带有状态码和文本的 data
  • 带有堆栈跟踪的错误实例
  • 随机抛出的值
import { Route } from "./+types/root";

export function ErrorBoundary({
  error,
}: Route.ErrorBoundaryProps) {
  if (isRouteErrorResponse(error)) {
    return (
      <>
        <h1>
          {error.status} {error.statusText}
        </h1>
        <p>{error.data}</p>
      </>
    );
  } else if (error instanceof Error) {
    return (
      <div>
        <h1>Error</h1>
        <p>{error.message}</p>
        <p>The stack trace is:</p>
        <pre>{error.stack}</pre>
      </div>
    );
  } else {
    return <h1>Unknown Error</h1>;
  }
}

2. 写一个 Bug

不建议故意抛出错误来强制错误边界呈现,以此作为控制流程的手段。错误边界主要是为了捕获代码中的意外错误。

export async function loader() {
  return undefined();
}

这将呈现步骤 1 中 UI 的 instanceof Error 分支。

这不仅适用于加载器,还适用于所有路由模块 API:加载器、操作、组件、头部、链接和元数据。

3. 在加载器/操作中抛出数据

第 2 条中的规则也有例外,尤其是 404 错误。当加载器找不到渲染页面所需的内容时,你可以有意地向最近的错误边界 throw data()(带有适当的状态码)。抛出一个 404,然后继续。

import { data } from "react-router";

export async function loader({ params }) {
  let record = await fakeDb.getRecord(params.id);
  if (!record) {
    throw data("Record Not Found", { status: 404 });
  }
  return record;
}

这将呈现步骤 1 中 UI 的 isRouteErrorResponse 分支。

4. 嵌套的错误边界

当抛出错误时,将呈现“最近的错误边界”。考虑这些嵌套路由:

// ✅ has error boundary
route("/app", "app.tsx", [
  // ❌ no error boundary
  route("invoices", "invoices.tsx", [
    // ✅ has error boundary
    route("invoices/:id", "invoice-page.tsx", [
      // ❌ no error boundary
      route("payments", "payments.tsx"),
    ]),
  ]),
]);

下表显示了根据错误来源将呈现哪个错误边界:

错误来源 呈现的边界
app.tsx app.tsx
invoices.tsx app.tsx
invoice-page.tsx invoice-page.tsx
payments.tsx invoice-page.tsx

错误净化

在生产模式下,服务器上发生的任何错误在发送到浏览器之前都会被自动净化,以防止泄露任何敏感的服务器信息(如堆栈跟踪)。

这意味着在生产环境中,抛出的 Error 在浏览器中将显示通用消息且没有堆栈跟踪。原始错误在服务器上保持不变。

另请注意,使用 throw data(yourData) 发送的数据不会被净化,因为那里的数据是意图要被渲染的。

文档和示例 CC 4.0
编辑