Dev Study
← 解説「loading.tsx — ページ準備中の表示」に戻る

サンプルコードで身につける: loading.tsx — ページ準備中の表示

解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。

1最小の loading.tsx

ファイルを置くだけで動く loading.tsx の最小形です。import も登録も不要で、同じフォルダの page.tsx の準備中に自動でこの表示に切り替わります。

// app/posts/loading.tsx
// → /posts の準備中、自動でこれが表示される
export default function Loading() {
  return <p>読み込み中...</p>;
}

// どこにも import しなくてよい。
// 「loading.tsx という名前で置く」こと自体が登録になる。

2スケルトンUIで本物の形を先に見せる

「読み込み中...」の文字だけでなく、完成後のレイアウトに似せた灰色の箱(スケルトン)を出す例です。表示がガタッと切り替わる感覚が減るため、実務のローディング表示はこの形が主流です。

// app/posts/loading.tsx — 記事一覧の形をした仮の表示
export default function Loading() {
  return (
    <main>
      <div style={{ height: 24, width: 200, background: "#ddd" }} />
      <div style={{ height: 16, background: "#eee", marginTop: 12 }} />
      <div style={{ height: 16, background: "#eee", marginTop: 8 }} />
      <div style={{ height: 16, background: "#eee", marginTop: 8 }} />
    </main>
  );
}
// 完成後のページと同じ位置に箱を置いておくと、
// 本物に切り替わったとき画面がガタつかない。

3効く範囲はフォルダ単位

loading.tsx を置く場所によって効く範囲が変わることを、配置の比較で示した例です。サイト全体の保険として app 直下に置きつつ、特に時間のかかるページには専用のものを近くに置く、という二段構えが実務の型です。

// loading.tsx は「同じフォルダとその配下」にだけ効く
//
// app/
// ├── loading.tsx          ← サイト全体の保険(全ページに効く)
// ├── about/page.tsx       ← app/loading.tsx が使われる
// └── reports/
//     ├── loading.tsx      ← /reports 専用(こちらが優先)
//     └── page.tsx         ← 集計に時間がかかるページ
//
// 時間のかかるページには、そのページに合わせた
// 専用の loading.tsx を近くに置くのが定石。

4先に仮の表示、できたら本物

loading.tsx の動きを「即座に仮の表示を出し、準備が終わったら差し替える」という時間の流れとして実行する例です。重い処理を await している間もユーザーに無反応な画面を見せない、という仕組みの核心を体感できます。

TypeScript

5商品一覧のスケルトンカード

EC サイトの商品グリッドに合わせて、カード型のスケルトンを必要な枚数だけ並べる実務的な例です。配列から仮のカードを生成するので、デザイン変更でカード数が変わってもループの数字を変えるだけで済みます。

// app/products/loading.tsx — 商品グリッドの形をした仮表示
export default function Loading() {
  const placeholders = Array.from({ length: 6 }, (_, i) => i);
  return (
    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 16 }}>
      {placeholders.map((i) => (
        <div key={i}>
          <div style={{ height: 120, background: "#eee" }} /> {/* 画像の枠 */}
          <div style={{ height: 14, background: "#ddd", marginTop: 8 }} /> {/* 商品名 */}
          <div style={{ height: 14, width: 60, background: "#ddd", marginTop: 4 }} /> {/* 価格 */}
        </div>
      ))}
    </div>
  );
}