概要
Next.js App Router では、error.tsx を配置するとそのセグメント配下で発生したエラーを React の Error Boundary としてキャッチできる。
page.tsx での fetch エラーや例外をフォールバック UI で受け取り、reset() で再試行も提供できる。
インストール
# 追加インストールは不要
基本構成(error.tsx)
// app/dashboard/error.tsx
"use client";
import { useEffect } from "react";
type Props = {
error: Error & { digest?: string };
reset: () => void;
};
export default function DashboardError({ error, reset }: Props) {
useEffect(() => {
// エラーログ送信など
console.error(error);
}, [error]);
return (
<div className="flex flex-col items-center gap-4 py-16">
<p className="text-sm text-gray-600">データの読み込みに失敗しました</p>
<button
onClick={reset}
className="rounded bg-blue-600 px-4 py-2 text-sm text-white hover:bg-blue-700"
>
再試行する
</button>
</div>
);
}
エラーを発生させる page.tsx の例
// app/dashboard/page.tsx
async function fetchData() {
const res = await fetch("https://api.example.com/data");
if (!res.ok) throw new Error("データの取得に失敗しました");
return res.json();
}
export default async function DashboardPage() {
const data = await fetchData();
return <div>{JSON.stringify(data)}</div>;
}
global-error.tsx(ルートレイアウトのエラー用)
ルートの layout.tsx 自体でエラーが発生した場合は error.tsx ではキャッチできない。
app/global-error.tsx を用意することでカバーできる。
// app/global-error.tsx
"use client";
export default function GlobalError({
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<html>
<body>
<div className="flex flex-col items-center gap-4 py-16">
<p className="text-sm">予期しないエラーが発生しました</p>
<button onClick={reset} className="rounded bg-gray-800 px-4 py-2 text-sm text-white">
再読み込み
</button>
</div>
</body>
</html>
);
}
ポイント
error.tsxは必ず"use client"にする。Server Component 側のエラーをクライアントの Error Boundary が受け取る設計のためreset()を呼ぶと、そのセグメントのサーバーコンポーネントを再レンダリングしてリカバリを試みるerror.tsxは同階層のlayout.tsxの内側でしか機能しない。layout.tsx自体のエラーは親セグメントのerror.tsxまたはglobal-error.tsxでキャッチするerror.digestはサーバー側のエラー詳細が含まれる可能性がある(本番では外部に漏らさない)