跳到內容

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