😸

Next.jsでloading.tsxが呼ばれるタイミング

2025/02/27に公開

はじめに

loading.tsxApp Routerを使用している場合に、特定の条件で呼ばれる。

loading.tsxが呼ばれるタイミング

1. Suspenseのフォールバックとして

loading.tsxは、layout.tsxの子コンポーネントが非同期レンダリングされるときに自動的に表示されます。
例えば、次のようなloading.tsxがあるとします。

app/loading.tsx
export default function Loading() {
  return <p>Loading...</p>;
}

この場合、次のような条件でloading.tsxが表示される。

条件① ページコンポーネントが非同期

app/page.tsx
export default async function Page() {
  await new Promise((resolve) => setTimeout(resolve, 2000)); // 2秒待機
  return <h1>Home Page</h1>;
}

page.tsxのロードに時間がかかるため、loading.tsxが一時的に表示される。

条件② レイアウトの子コンポーネントが非同期

app/layout.tsx
export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <div>
      <h1>My App</h1>
      {children}
    </div>
  );
}
app/some-page/page.tsx
export default async function SomePage() {
  await new Promise((resolve) => setTimeout(resolve, 3000)); // 3秒待機
  return <h1>Some Page</h1>;
}

some-pageが遅延ロードされると、その間loading.tsxが表示される。

2. ネストしたルートの loading.tsx

ルートごとにloading.tsxを定義できるため、app配下のディレクトリごとにloading.tsxを作成すると、そのルートに対して適用されます。
例えば:

フォルダ構成
app/
 ├── layout.tsx
 ├── loading.tsx   ← 全ページのローディングUI
 ├── page.tsx
 ├── dashboard/
 │   ├── layout.tsx
 │   ├── loading.tsx   ← `/dashboard` 専用のローディングUI
 │   ├── page.tsx

この場合、

  • /dashboardにアクセスした場合はapp/dashboard/loading.tsx
  • /やその他のページではapp/loading.tsxが表示される。

loading.tsx が呼ばれない場合

以下のようなケースではloading.tsxは表示されません。

  1. ページが同期的にレンダリングされる場合
    • async を使わずにコンポーネントがすぐにレンダリングされると loading.tsx は不要。
  2. データフェッチがクライアントコンポーネント内で行われる場合
    • useEffectでデータを取得する場合は、loading.tsxではなく、クライアントコンポーネント内でuseStateを使ってローディング状態を管理する必要がある。
  3. suspenseを手動で使っていない場合
    • loading.tsxは自動的にSuspenseのフォールバックとして適用されるが、ページコンポーネントやレイアウトが同期的にレンダリングされると適用されない。

Discussion