Menu

error.js

errorファイルを使用することで、予期しないランタイムエラーを処理し、フォールバックUIを表示することができます。

error.js特殊ファイル
app/dashboard/error.tsx
TypeScript
'use client' // エラーバウンダリーはClient Componentsである必要があります
 
import { useEffect } from 'react'
 
export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  useEffect(() => {
    // エラーをエラーレポートサービスにログします
    console.error(error)
  }, [error])
 
  return (
    <div>
      <h2>Something went wrong!</h2>
      <button
        onClick={
          // セグメントを再レンダリングすることでリカバリーを試みます
          () => reset()
        }
      >
        Try again
      </button>
    </div>
  )
}

error.jsはルートセグメントとそのネストされた子要素をReact Error Boundaryでラップします。バウンダリー内でエラーがスローされた場合、errorコンポーネントがフォールバックUIとして表示されます。

error.jsの動作方法

補足

  • React DevToolsを使用すると、エラーバウンダリーを切り替えてエラー状態をテストできます。
  • エラーを親エラーバウンダリーまでバブルアップさせたい場合は、errorコンポーネントをレンダリングする際にthrowを使用できます。

リファレンス

Props

error

error.js Client Componentに転送されるErrorオブジェクトのインスタンス。

補足:開発中は、Client Componentに転送されたErrorオブジェクトはシリアライズされ、デバッグを容易にするために元のエラーのmessageを含みます。ただし、本番環境ではこの動作は異なります。エラーに含まれる機密情報が誤ってユーザーに公開されるのを防ぐためです。

error.message

  • Client Componentsから転送されたエラーは、元のErrorメッセージを表示します。
  • Server Componentsから転送されたエラーは、識別子を含む汎用メッセージを表示します。これは機密情報の漏洩を防ぐためです。errors.digestの下にある識別子を使用して、対応するサーバー側ログと照合できます。

error.digest

スローされたエラーの自動生成ハッシュ。サーバー側ログの対応するエラーと照合するために使用できます。

reset

エラーの原因は、時に一時的である場合があります。このような場合、再度試行することでエラーが解決される可能性があります。

エラーコンポーネントはreset()関数を使用して、ユーザーがエラーからのリカバリーを試行するようプロンプトできます。実行時、この関数はエラーバウンダリーのコンテンツを再レンダリングしようとします。成功した場合、フォールバックエラーコンポーネントは再レンダリングの結果に置き換えられます。

app/dashboard/error.tsx
TypeScript
'use client' // エラーバウンダリーは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>
  )
}

グローバルエラー

あまり一般的ではありませんが、root layoutやテンプレートを使用してルートappディレクトリに配置されたglobal-error.jsxでエラーを処理できます。多言語化を活用している場合も同様です。グローバルエラーUIは、エラーページが必要とする独自の<html>および<body>タグ、グローバルスタイル、フォント、またはその他の依存関係を定義する必要があります。このファイルは、アクティブな場合、root layoutまたはテンプレートの代わりになります。

補足:エラーバウンダリーはClient Componentsである必要があるため、global-error.jsxではmetadataおよびgenerateMetadataのエクスポートはサポートされていません。代わりに、React<title>コンポーネントを使用できます。

app/global-error.tsx
TypeScript
'use client' // エラーバウンダリーはClient Componentsである必要があります
 
export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    // global-errorはhtmlおよびbodyタグを含む必要があります
    <html>
      <body>
        <h2>Something went wrong!</h2>
        <button onClick={() => reset()}>Try again</button>
      </body>
    </html>
  )
}

カスタムエラーバウンダリーを使用した適切なエラーリカバリー

クライアント側でレンダリングが失敗した場合、より良いユーザー体験のため、最後に既知のサーバーレンダリング済みUIを表示することが有用です。

GracefullyDegradingErrorBoundaryは、エラー発生前の現在のHTMLをキャプチャして保存するカスタムエラーバウンダリーの例です。レンダリングエラーが発生した場合、キャプチャされたHTMLを再レンダリングし、ユーザーに通知する永続的な通知バーを表示します。

app/dashboard/error.tsx
TypeScript
'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) {
      // ハイドレーションなしで現在のHTMLコンテンツをレンダリングします
      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">
              ページレンダリング中にエラーが発生しました
            </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