Next.js 14 App Router - Loading UI & Streaming
ソース: https://nextjs.org/docs/14/app/building-your-application/routing/loading-ui-and-streaming
loading.js
loading.js で React Suspense を使ったローディングUIを作成。
tsx
// app/dashboard/loading.tsx
export default function Loading() {
return <LoadingSkeleton />
}動作
loading.jsはlayout.jsの中にネストpage.jsとその配下を<Suspense>境界で自動ラップ
<Layout>
<Suspense fallback={<Loading />}>
<Page />
</Suspense>
</Layout>特徴:
- ナビゲーションは即座(サーバーセントリックルーティングでも)
- ナビゲーションは中断可能(ルートコンテンツのロード完了を待たずに別ルートへ移動可能)
- 新しいルートセグメントのロード中も共有レイアウトはインタラクティブ
Streaming with Suspense
loading.js に加え、独自の <Suspense> 境界を手動で作成可能。
SSR の課題と Streaming の解決
従来のSSR(順次・ブロッキング):
- サーバーでページの全データをフェッチ
- サーバーでHTMLをレンダリング
- HTML, CSS, JS をクライアントに送信
- 非インタラクティブUIを表示
- React がハイドレーション → インタラクティブ化
Streaming:
- ページのHTMLをチャンクに分割して順次送信
- データのロード完了を待たずにUIの一部を先に表示
- 優先度の高いコンポーネントを先に送信可能
メリット
- TTFB の改善
- FCP の改善
- TTI の改善(特に低速デバイス)
Suspense の使い方
tsx
import { Suspense } from 'react'
import { PostFeed, Weather } from './Components'
export default function Posts() {
return (
<section>
<Suspense fallback={<p>Loading feed...</p>}>
<PostFeed />
</Suspense>
<Suspense fallback={<p>Loading weather...</p>}>
<Weather />
</Suspense>
</section>
)
}Suspense の利点:
- Streaming Server Rendering: サーバーからクライアントへHTMLを順次レンダリング
- Selective Hydration: ユーザーインタラクションに基づいてハイドレーション優先度を決定
SEO
generateMetadata内のデータフェッチが完了するまでUIストリーミングを待機 →<head>タグが最初に含まれる- ストリーミングはサーバーレンダリングのためSEOに影響なし
ステータスコード
- ストリーミング中は
200が返される - レスポンスヘッダーは既に送信済みのため、ステータスコードの変更は不可
redirectやnotFoundはストリーミングコンテンツ内でエラーを通知- SEO には影響しない