跳到内容

error.js

error 文件允许您处理意外的运行时错误并显示备用 UI。

error.js special file
app/dashboard/error.tsx
'use client' // Error boundaries must be Client Components
 
import { useEffect } from 'react'
 
export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  useEffect(() => {
    // Log the error to an error reporting service
    console.error(error)
  }, [error])
 
  return (
    <div>
      <h2>Something went wrong!</h2>
      <button
        onClick={
          // Attempt to recover by trying to re-render the segment
          () => reset()
        }
      >
        Try again
      </button>
    </div>
  )
}

error.js 将路由段及其嵌套子项包装在 React 错误边界中。当错误在边界内抛出时,error 组件将作为备用 UI 显示。

How error.js works

须知:

  • React DevTools 允许您切换错误边界以测试错误状态。
  • 如果您希望错误冒泡到父级错误边界,您可以在渲染 error 组件时 throw

参考

属性

error

一个 Error 对象的实例,转发到 error.js 客户端组件。

重要提示: 在开发过程中,转发到客户端的 Error 对象将被序列化,并包含原始错误的 message 以便调试。然而,此行为在生产环境中有所不同,以避免将错误中可能包含的敏感细节泄露给客户端。

error.message

  • 从客户端组件转发的错误显示原始的 Error 消息。
  • 从服务器组件转发的错误会显示带有标识符的通用消息。这是为了防止泄露敏感细节。您可以使用 errors.digest 下的标识符来匹配相应的服务器端日志。

error.digest

抛出错误的自动生成哈希。它可用于匹配服务器端日志中的相应错误。

reset

有时错误的原因可能是暂时的。在这种情况下,重试可能会解决问题。

错误组件可以使用 reset() 函数提示用户尝试从错误中恢复。执行后,该函数将尝试重新渲染错误边界的内容。如果成功,备用错误组件将被重新渲染的结果替换。

app/dashboard/error.tsx
'use client' // Error boundaries must be Client Components
 
export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <div>
      <h2>Something went wrong!</h2>
      <button onClick={() => reset()}>Try again</button>
    </div>
  )
}

示例

全局错误

虽然不太常见,但您可以使用位于根应用程序目录中的 global-error.jsx 来处理根布局或模板中的错误,即使是利用了国际化。全局错误 UI 必须定义自己的 <html><body> 标签、全局样式、字体或错误页面所需的其他依赖项。此文件在激活时会替换根布局或模板。

重要提示:错误边界必须是客户端组件,这意味着 global-error.jsx 中不支持metadatagenerateMetadata 导出。作为替代方案,您可以使用 React 的 <title> 组件。

app/global-error.tsx
'use client' // Error boundaries must be Client Components
 
export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    // global-error must include html and body tags
    <html>
      <body>
        <h2>Something went wrong!</h2>
        <button onClick={() => reset()}>Try again</button>
      </body>
    </html>
  )
}

使用自定义错误边界实现优雅的错误恢复

当客户端渲染失败时,显示上次已知的服务器渲染 UI 可能有助于提供更好的用户体验。

GracefullyDegradingErrorBoundary 是一个自定义错误边界的示例,它在错误发生前捕获并保留当前的 HTML。如果发生渲染错误,它会重新渲染捕获的 HTML 并显示一个持久的通知栏来通知用户。

app/dashboard/error.tsx
'use client'
 
import React, { Component, ErrorInfo, ReactNode } from 'react'
 
interface ErrorBoundaryProps {
  children: ReactNode
  onError?: (error: Error, errorInfo: ErrorInfo) => void
}
 
interface ErrorBoundaryState {
  hasError: boolean
}
 
export class GracefullyDegradingErrorBoundary extends Component<
  ErrorBoundaryProps,
  ErrorBoundaryState
> {
  private contentRef: React.RefObject<HTMLDivElement | null>
 
  constructor(props: ErrorBoundaryProps) {
    super(props)
    this.state = { hasError: false }
    this.contentRef = React.createRef()
  }
 
  static getDerivedStateFromError(_: Error): ErrorBoundaryState {
    return { hasError: true }
  }
 
  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    if (this.props.onError) {
      this.props.onError(error, errorInfo)
    }
  }
 
  render() {
    if (this.state.hasError) {
      // Render the current HTML content without hydration
      return (
        <>
          <div
            ref={this.contentRef}
            suppressHydrationWarning
            dangerouslySetInnerHTML={{
              __html: this.contentRef.current?.innerHTML || '',
            }}
          />
          <div className="fixed bottom-0 left-0 right-0 bg-red-600 text-white py-4 px-6 text-center">
            <p className="font-semibold">
              An error occurred during page rendering
            </p>
          </div>
        </>
      )
    }
 
    return <div ref={this.contentRef}>{this.props.children}</div>
  }
}
 
export default GracefullyDegradingErrorBoundary

版本历史

版本更改
v15.2.0在开发中也显示 global-error
v13.1.0引入了 global-error
v13.0.0引入了 error