作成日: 2023-8-19
更新日: 2023-9-28
Next.jsのApp Routerでは、エラー発生時のUIを表現できるerror.js
というファイルが存在します。
error.js
はURLごとに異なるUIのエラー画面を用意できるので、柔軟性もあります。
また、リロードなどによらずエラーから回復させる機能も持っています。
error.js
はReact18のReact Error Boundaryをベースにした機能です。
React Error Boundaryの挙動について解説します。
Next.jsのApp Routerで使えるerror.js
は、React18で導入されたReact Error Boundary
をベースに作られています。React Error Boundary
の概要についても解説しておきます。
React Error Boundary
とは、Reactアプリケーションでレンダリング中にエラーが発生した際に、エラーメッセージやfallbackのUIを表示するための特別なコンポーネントです。
デフォルトでは、エラーが発生すると、Reactはエラーを含むUIを画面から削除しますが、エラーバウンダリーを使用することでこれを防ぐことができます。
エラーが発生する可能性のあるコンポーネントをError Boundary
コンポーネントでラップするだけです。
<ErrorBoundary fallback={<p>エラーが発生しました</p>}>
<ArticleList />
</ErrorBoundary>
具体的にerror.js
の使い方について解説します。
まずは、エラーが発生する可能性のあるページのディレクトリにerror.js
を追加します。
├── app
│ ├── admin
│ │ ├── layout.tsx
│ │ ├── error.tsx // 追加する
│ │ ├── page.tsx
error.js
はClient Componentsでしか使うことができないので、use client
をファイルの先頭につける必要があります。
'use client'
export default function Error({
error,
reset,
}: {
error: Error
reset: () => void
}) {
return (
<div>
<h2>{ error.message }</h2>
<button onClick={() => reset()}>再レンダリングする</button>
</div>
)
}
error.js
では、Error
オブジェクトとreset()
を引数に取ることができます。Error
オブジェクトには、page.js
もしくはその子コンポーネントで発生したError
オブジェクトが入っています。reset()
関数は、エラーが発生しているコンポーネントの再レンダリングを実行してくれます。
error.js
は、同じ階層にあるlauout.js
もしくはtemplate.js
でのエラーをキャッチすることができない<ErrorBoundary>
コンポーネントがlayout.js
もしくはtemplate.js
にラップされているためです。
さらに上の階層にあるerror.js
であればエラーをキャッチすることができます。
イメージ的には以下のようになっています。
<layout>
<ErrorBoundary>
<Page />
</ErrorBoundary>
</layout>
- Root Layoutsのlayout.js
もしくは template.js
のエラーをキャッチするためには、global-error.js
を配置する必要がある
以下のディレクトリ構成におけるapp/layout.js
(appディレクトリ直下にある)のエラーはerror.js
でエラーをキャッチできません。
├── src
│ └── app
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.tsx
│ ├── page.tsx
もし、app/layout.js
で発生したエラーをキャッチさせたい場合は、app/global-error.js
を配置する必要があります。global-error.js
を配置する場合、<html>
と<body>
タグをそのファイルに必ず含める 必要があります。
// app/global-error.tsx
'use client'
export default function GlobalError({
error,
reset,
}: {
error: Error
reset: () => void
}) {
return (
<html>
<body>
<h2>{ error.message }</h2>
<button onClick={() => reset()}>再レンダリングする</button>
</body>
</html>
)
}
error.js
は全てのディレクトリに配置する必要はありません。
エラーの発生する可能性のあるページでのみ使うことが適切だと公式ドキュメントにも書かれているので、利用は必要な箇所のみにしましょう。