コンテンツにスキップ

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 Boundary でラップします。境界内でエラーが発生すると、error コンポーネントがフォールバック UI として表示されます。

How error.js works

知っておくと良いこと:

  • React DevTools を使用すると、エラー境界を切り替えてエラー状態をテストできます。
  • エラーを親のエラー境界に伝播させたい場合は、error コンポーネントをレンダリングする際に throw できます。

リファレンス

Props

error

error.js クライアントコンポーネントに渡される Error オブジェクトのインスタンス。

知っておくと良いこと: 開発中は、クライアントに渡される 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 では metadata および generateMetadata エクスポートがサポートされていないことを意味します。代替として、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.0global-error が導入されました。
v13.0.0error が導入されました。