ウェブエンジニア問題集

ローディングとエラー処理 — loading.tsx・error.tsx・not-foundの使い方

データ取得には「待ち時間」と「失敗」がつきものです。読み込み中に真っ白な画面を見せたり、エラーでアプリ全体が落ちたりしては、良いユーザー体験になりません。App Routerでは、特別なファイルを置くだけでローディング表示・エラー画面・404ページを宣言的に用意できます。

この章では、loading.tsxerror.tsxnot-found.tsx の3つを押さえます。

学習者学習者

fetch を待ってる間ってどうすればいいの? useState でローディング管理するのは面倒だなあ…。

loading.tsx — 読み込み中のUI

フォルダに loading.tsx を置くと、そのページのデータ取得が終わるまでの間、自動でそのUIが表示されます。useState でローディングフラグを管理する必要はありません。

// src/app/posts/loading.tsx
export default function Loading() {
  return <p>読み込み中...</p>;
}
app/
└── posts/
    ├── page.tsx       ← データ取得に時間がかかるページ
    └── loading.tsx    ← その間に表示される(自動)
先生先生

裏側ではReactの Suspense が使われていて、Next.jsが page.tsx を自動でSuspenseで包んでくれている。だから君は loading.tsx を置くだけでいいんだ。

待ち時間にローディングUIを見せて安心させるイメージ

error.tsx — エラー時のUI

データ取得や描画中にエラーが投げられたとき、error.tsx を置いておくとアプリ全体を巻き込まず、その範囲だけエラーUIに差し替えられます。

error.tsx には2つの決まりがあります。

  • 必ず "use client"(Client Component)にする
  • error(発生したエラー)と reset(再試行用の関数)を props で受け取れる

props の構造:

prop説明
errorError発生したエラーオブジェクト(error.message など)
reset() => voidその範囲を再レンダリングして復帰を試みる関数
// src/app/posts/error.tsx
"use client";
 
export default function Error({
  error,
  reset,
}: {
  error: Error;
  reset: () => void;
}) {
  return (
    <div>
      <p>エラーが発生しました: {error.message}</p>
      <button onClick={() => reset()}>もう一度試す</button>
    </div>
  );
}

not-found.tsx と notFound() — 404ページ

「指定された記事が存在しない」ようなケースでは、404を返したいものです。App Routerでは2つを組み合わせます。

  • not-found.tsx:404のときに表示するUI
  • notFound():コード中から「これは404だ」と宣言する関数(next/navigation
// src/app/blog/[slug]/page.tsx
import { notFound } from "next/navigation";
 
export default async function Post({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const res = await fetch(`https://api.example.com/posts/${slug}`);
 
  if (!res.ok) {
    notFound(); // ← ここで処理を中断し、not-found.tsx を表示
  }
 
  const post = await res.json();
  return <h1>{post.title}</h1>;
}
// src/app/blog/[slug]/not-found.tsx
export default function NotFound() {
  return <p>記事が見つかりませんでした。</p>;
}
学習者学習者

notFound() を呼ぶと、その後の処理は実行されないの?

はい。notFound() は内部的に特別な例外を投げて処理を中断し、最も近い not-found.tsx を表示します。return を書かなくてもそこで止まるため、「無ければ404、あれば表示」がすっきり書けます。

3つのファイルの関係

これまでの予約ファイルを、表示されるタイミングで整理します。

ファイル表示されるときClient必須?
loading.tsxデータ取得・描画の完了を待つ間いいえ
error.tsx描画中にエラーが投げられたときはい"use client"
not-found.tsxnotFound() が呼ばれた / 未定義のURLいいえ

まとめ

  • loading.tsx を置くだけで、データ取得の待ち時間に自動でローディングUIが出る(裏側はSuspense)
  • error.tsx"use client" 必須。errorreset を受け取り、その範囲だけをエラーUIに差し替える
  • 404は notFound()(コードから宣言)+ not-found.tsx(表示UI)の組み合わせ
  • これらはフォルダ単位で置けるので、セクションごとに最適なUIを用意できる

次の章では、検索エンジンとSNSでの見え方を左右する メタデータとSEO を扱います。generateMetadata で、ページごとに title やOGP画像を動的に設定する方法を学びます。