概要
app/global-error.tsx を使い、ルートレイアウトを含む最上位のランタイムエラーをキャッチする。error.tsx はセグメント内のエラーのみ対象で、ルートレイアウト内のエラーは捕捉できない。reset 関数でリカバリーボタンを実装するパターンを示す。
インストール
# 追加インストールは不要
実装
error.tsx / global-error.tsx の責務の違い
app/
layout.tsx ← ルートレイアウト(global-error.tsx が守る)
global-error.tsx ← ルートレイアウトを含む最上位エラーをキャッチ
error.tsx ← app/ 直下のセグメントエラーをキャッチ
page.tsx
dashboard/
layout.tsx ← このレイアウト内のエラーは dashboard/error.tsx が守る
error.tsx
page.tsx
global-error.tsx
// app/global-error.tsx
"use client";
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
// global-error.tsx はルートレイアウトを置き換えるため
// 独自の <html> と <body> が必要
<html lang="ja">
<body>
<main className="flex min-h-screen flex-col items-center justify-center p-8 text-center">
<div className="max-w-md">
<h1 className="mb-2 text-4xl font-bold text-red-500">
予期しないエラー
</h1>
<p className="mb-2 text-gray-600">
アプリケーションで問題が発生しました。
</p>
{process.env.NODE_ENV === "development" && (
<p className="mb-4 rounded bg-gray-100 p-3 text-left text-xs text-gray-500">
{error.message}
</p>
)}
{error.digest && (
<p className="mb-4 text-xs text-gray-400">
エラーID: {error.digest}
</p>
)}
<div className="flex justify-center gap-3">
<button
onClick={reset}
className="rounded bg-blue-600 px-5 py-2 text-sm text-white hover:bg-blue-700"
>
もう一度試す
</button>
<a
href="/"
className="rounded border border-gray-300 px-5 py-2 text-sm text-gray-700 hover:bg-gray-50"
>
トップに戻る
</a>
</div>
</div>
</main>
</body>
</html>
);
}
セグメント用 error.tsx(比較用)
// app/error.tsx
"use client";
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
// error.tsx はルートレイアウトの中に入るため <html>/<body> 不要
<main className="flex min-h-screen flex-col items-center justify-center p-8 text-center">
<h2 className="mb-4 text-2xl font-semibold text-gray-800">
エラーが発生しました
</h2>
<button
onClick={reset}
className="rounded bg-blue-600 px-5 py-2 text-sm text-white hover:bg-blue-700"
>
再試行
</button>
</main>
);
}
エラーをわざと発生させる例(動作確認用)
// app/page.tsx
"use client";
export default function Page() {
function throwError() {
throw new Error("テスト用エラー");
}
return (
<main className="p-8">
<h1 className="mb-4 text-2xl font-bold">エラーテスト</h1>
<button
onClick={throwError}
className="rounded bg-red-500 px-4 py-2 text-sm text-white hover:bg-red-600"
>
エラーを発生させる
</button>
</main>
);
}
ポイント
global-error.tsxはルートレイアウトを置き換えるため、独自の<html>と<body>が必要。error.tsxはレイアウトの中に入るため不要global-error.tsxは 本番ビルド(next build+next start)でのみ動作する。開発中(next dev)はオーバーレイが表示されるreset()を呼ぶとエラー境界をリセットして再レンダリングを試みる。サーバー側エラーの場合は再フェッチも行われるerror.digestはサーバーサイドエラーの識別子。本番環境でエラーログと照合するために使う(クライアントに詳細を出さずに済む)error.tsxとの使い分け:error.tsxはページやレイアウト単位のエラー。global-error.tsxはルートレイアウト自体が壊れた場合(Provider や<html>のエラー等)の最終防衛ライン