1. ホーム
  2. Next.js

【Next.js】error.tsx でエラー画面を作る方法|reset で再試行できるUIを実装する

Share

データ取得に失敗したり、想定外の値でコードが例外を投げたり、Web アプリではエラーが起きることを避けられません。何も対策していないと、エラーが起きた瞬間に画面全体が真っ白になり、ユーザーは何が起きたのか分かりません。Next.js の App Router では、error.tsx というファイルを置くだけで、こうしたエラーを受け止めて専用のエラー画面を表示できます。この記事では、error.tsx の基本、なぜ "use client" が必要なのか、渡ってくる errorreset の使い方までを、初心者向けに解説します。

error.tsx はエラーの「受け皿」になる

page.tsx と同じフォルダに error.tsx を置くと、そのページ(や配下のコンポーネント)の描画中にエラーが投げられたとき、Next.js がそれをキャッチして error.tsx の内容を代わりに表示します。エラーはそのフォルダの範囲内で受け止められるため、アプリ全体がクラッシュすることはありません。React の「エラーバウンダリ」という仕組みを、ファイルを置くだけで使えるようにしたものです。

app/dashboard/error.tsx
"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 が役立ちます。

app/dashboard/error.tsx
"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 と合わせて用意しておくと、読み込みと失敗の両方に配慮した親切なアプリになります。

参考ページ