
この記事では、loading.tsxとSuspenseの役割や使い方、それぞれの違いについて説明します。
Suspenseは、Reactが提供しているコンポーネントです。
Suspenseでラップした子コンポーネントがレンダリング中にSuspend(表示に必要なデータがそろっていない状態)した場合、データの準備ができるまで、fallbackプロパティに指定したUIを表示します。
↓簡単なコードですがこんな感じ。
import { Suspense } from "react";
import { getArticle } from "../lib/article";
async function Article() {
const data = await getArticle();
return <div>{data.title}</div>;
}
export default function SamplePage() {
return (
<Suspense fallback={<p>準備中です。。。</p>}>
<Article />
</Suspense>
);
}
上記のコードでは、Articleコンポーネント内のgetArticleの処理が完了するまで、fallbackに指定した以下のUIが表示されます。
<p>準備中です。。。</p>
fallbackには、スケルトンスクリーンやスピナー、ローディングメッセージなどを指定できます。ローディングUIを表示することで、ユーザーに処理中であることを伝え、画面が固まったように感じるのを防ぎます。
loading.tsxはNext.jsのApp Routerで使用できる特殊なファイルです。
ルートセグメント内にloading.tsxを配置すると、Next.jsがその階層のpage.tsxとその子コンポーネントを自動的にSuspenseで囲ってくれます。
たとえば、以下のようなファイル構成だとします。
app/
└─ articles/
├─ loading.tsx
└─ page.tsx
その場合のコードは以下のようなコードになります。
loading.tsx
export default function Loading() {
return <p>準備中です。。。</p>
}
page.tsx
import { getArticle } from "../lib/article";
export default async function SamplePage() {
const data = await getArticle();
return <div>{data.title}</div>
}
このルートに移動した際、ページのコンテンツがまだ準備できていない場合はloading.tsxのUIが表示され、コンテンツの準備が完了するとpage.tsxの内容が表示されます。
ざっくりいうと、スコープの違いです。
loading.tsxは、ルートセグメント単位でローディングUIを表示したい場合に向いています。
Suspenseは、コンポーネント毎にラップしfallbackプロパティを指定することが可能なため、ページ内の一部にローディングUIを指定したい場合や細かくローディング状態を制御したい場合はSuspenseを利用することになります。
loading.tsxとSuspenseはどちらか一方しか使えないわけではなく、併用することもできます。
ルートセグメント単位のローディングにはloading.tsxを使用し、ページ内の一部分にSuspenseを使用するといったこともできます。
このように使い分けると、それぞれのコンテンツを準備ができた順番に表示ができるため、ユーザーに待ち時間を感じさせにくくなります。
loading.tsxとSuspenseは、どちらもコンテンツの準備中にローディングUIを表示するための仕組みです。
loading.tsxはルートセグメント単位でローディングUIを設定したい場合に向いており、Suspenseはページ内の一部分だけにローディングUIを設定したい場合に向いています。
どちらか一方を選ぶのではなく、ルートセグメント単位にはloading.tsx、部分的な読み込みにはSuspenseというように、表示したい範囲に応じて使い分けることが大切です。