← 解説「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>
);
}