データ取得に失敗したり、想定外の値でコードが例外を投げたり、Web アプリではエラーが起きることを避けられません。何も対策していないと、エラーが起きた瞬間に画面全体が真っ白になり、ユーザーは何が起きたのか分かりません。Next.js の App Router では、error.tsx というファイルを置くだけで、こうしたエラーを受け止めて専用のエラー画面を表示できます。この記事では、error.tsx の基本、なぜ "use client" が必要なのか、渡ってくる error と reset の使い方までを、初心者向けに解説します。
目次
error.tsx はエラーの「受け皿」になる
page.tsx と同じフォルダに error.tsx を置くと、そのページ(や配下のコンポーネント)の描画中にエラーが投げられたとき、Next.js がそれをキャッチして error.tsx の内容を代わりに表示します。エラーはそのフォルダの範囲内で受け止められるため、アプリ全体がクラッシュすることはありません。React の「エラーバウンダリ」という仕組みを、ファイルを置くだけで使えるようにしたものです。
"use client"; // error.tsx は必ず Client Component にする
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<div>
<h2>エラーが発生しました</h2>
<button onClick={() => reset()}>もう一度試す</button>
</div>
);
}
このファイルを置いておけば、同じフォルダの page.tsx がエラーを投げたときに、真っ白な画面ではなく「エラーが発生しました」という案内が表示されます。ユーザーに状況を伝えられるだけで、アプリの信頼感は大きく変わります。
なぜ “use client” が必要なのか
error.tsx の先頭には、必ず "use client" を書きます。これは error.tsx を Client Component(ブラウザ側で動くコンポーネント)にするための宣言です。理由は2つあります。1つは、エラーバウンダリの仕組み自体がクライアント側の機能であること。もう1つは、後述する reset ボタンのクリックのようなユーザー操作(イベント)を扱う必要があるためです。イベントハンドラは Client Component でしか使えないため、error.tsx はクライアント側で動く必要があります。
"use client" を書き忘れると、エラー画面が正しく動かないので、error.tsx を作るときはまず1行目に "use client"、と覚えておきましょう。
error と reset の2つの props
error.tsx のコンポーネントには、Next.js から2つの props が渡されます。それぞれの役割を押さえておきましょう。
| props | 役割 |
|---|---|
error | 発生した Error オブジェクト。error.message でメッセージを取得できる。digest はサーバー側で記録されたエラーの識別子 |
reset | エラーが起きた範囲を再描画し、処理をやり直すための関数 |
error を使えば、エラーの内容に応じたメッセージを出せます。ただし、本番環境では詳細なエラーメッセージがそのまま渡らないことがある(情報漏えいを防ぐため)点は覚えておきましょう。開発中の原因調査には error.message が役立ちます。
"use client";
import { useEffect } from "react";
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
// エラーを記録(ログ送信など)したいときは useEffect で
useEffect(() => {
console.error(error);
}, [error]);
return (
<div>
<h2>問題が発生しました</h2>
<p>時間をおいて、もう一度お試しください。</p>
<button onClick={() => reset()}>再試行</button>
</div>
);
}
reset で再試行できるようにする
reset は、エラーが起きた範囲をもう一度描画し直すための関数です。一時的な通信エラーなど、「やり直せば直るかもしれない」種類のエラーでは、この reset をボタンに結びつけておくと、ユーザーがページ全体を再読み込みしなくても、その場でリトライできます。
onClick={() => reset()} のようにボタンに設定すると、クリックのたびに Next.js がエラーの起きたコンポーネントの再描画を試みます。取得先が復旧していれば、今度は正常に表示されます。ユーザーに「詰み」を感じさせない、親切なエラー画面になります。
効く範囲と global-error.tsx
error.tsx は、loading.tsx と同じように、置いたフォルダとその配下で発生したエラーを受け止めます。ページごとに違うエラー画面を用意したり、上位フォルダに1つ置いて配下全体をカバーしたりできます。フォルダ構成でイメージすると分かりやすいです。
app/
├─ error.tsx ← 配下の広い範囲のエラーを受け止める
├─ global-error.tsx ← ルートレイアウト自体のエラー用(最後の砦)
└─ dashboard/
├─ error.tsx ← dashboard 内のエラーだけを受け止める
└─ page.tsx
1つ注意したいのは、error.tsx は同じ階層の layout.tsx で起きたエラーは受け止められないという点です。レイアウト自体が壊れるようなケースに備えるのが global-error.tsx で、これはアプリ全体のもっとも外側でエラーをキャッチする「最後の砦」です。global-error.tsx はルートレイアウトを置き換えるため、<html> と <body> タグを自分で含める必要があります。通常のエラーは各フォルダの error.tsx で受け、全体の保険として global-error.tsx を用意する、という二段構えが基本です。
まとめ
Next.js App Router の error.tsx は、ページや配下のコンポーネントで起きたエラーを受け止め、アプリ全体をクラッシュさせずにエラー画面を表示するための仕組みです。React のエラーバウンダリをファイルを置くだけで使えるようにしたもので、必ず先頭に "use client" を書きます。コンポーネントには error(発生したエラー)と reset(やり直す関数)が渡され、reset をボタンに結びつければ、ユーザーはその場で再試行できます。フォルダ単位で効くため使い分けができ、レイアウト自体の破損に備える global-error.tsx と組み合わせると、堅牢なエラー処理が実現できます。loading.tsx と合わせて用意しておくと、読み込みと失敗の両方に配慮した親切なアプリになります。