Loading UIとストリーミング
特別なファイルloading.js
は、React Suspenseを使用して意味のあるLoading UIを作成するのに役立ちます。この規約を使用すると、ルートセグメントのコンテンツが読み込まれる間、サーバーから即時のローディング状態を表示できます。新しいコンテンツはレンダリングが完了すると自動的に入れ替わります。


即時のローディング状態
即時のローディング状態は、ナビゲーション時に即座に表示されるフォールバックUIです。スケルトンやスピナーなどのローディングインジケーター、またはカバーフォトやタイトルなどの将来の画面の小さくても意味のある部分を事前にレンダリングできます。これにより、ユーザーはアプリが応答していることを理解し、より良いユーザー体験を提供します。
フォルダ内にloading.js
ファイルを追加してローディング状態を作成します。


- TypeScript
- JavaScript
export default function Loading() {
// スケルトンを含む任意のUIをLoading内に追加できます。
return <LoadingSkeleton />
}
export default function Loading() {
// スケルトンを含む任意のUIをLoading内に追加できます。
return <LoadingSkeleton />
}
同じフォルダ内で、loading.js
はlayout.js
内にネストされます。これにより、page.js
ファイルとその下のすべての子が自動的に<Suspense>
境界でラップされます。


Good to know:
- ナビゲーションは、サーバー中心のルーティングでも即時に行われます。
- ナビゲーションは中断可能であり、ルートのコンテンツが完全に読み込まれるのを待たずに別のルートに移動できます。
- 共有レイアウトは、新しいルートセグメントが読み込まれる間もインタラクティブなままです。
推奨事項: Next.jsがこの機能を最適化しているため、ルートセグメント(レイアウトとページ)には
loading.js
規約を使用してください。
Suspenseを使用したストリーミング
loading.js
に加えて、自分のUIコンポーネント用に手動でSuspense境界を作成することもできます。App Routerは、Suspenseを使用したストリーミングをサポートしています。
Good to know:
- 一部のブラウザはストリーミングレスポンスをバッファリングします。レスポンスが1024バイトを超えるまでストリーミングされたレスポンスが表示されない場合があります。これは通常、「Hello World」アプリケーションにのみ影響しますが、実際のアプリケーションには影響しません。
ストリーミングとは何か?
ReactとNext.jsでストリーミングがどのように機能するかを理解するには、**サーバーサイドレンダリング(SSR)**とその制限を理解することが役立ちます。
SSRでは、ユーザーがページを見て操作できるようになる前に完了する必要がある一連のステップがあります:
- まず、指定されたページのすべてのデータがサーバーで取得されます。
- 次に、サーバーがページのHTMLをレンダリングします。
- ページのHTML、CSS、およびJavaScriptがクライアントに送信されます。
- 生成されたHTMLとCSSを使用して非インタラクティブなユーザーインターフェースが表示されます。
- 最後に、Reactがユーザーインターフェースをハイドレートしてインタラクティブにします。


これらのステップは順次かつブロッキングであり、サーバーはすべてのデータが取得されて初めてページのHTMLをレンダリングできます。また、クライアントでは、ページ内のすべてのコンポーネントのコードがダウンロードされて初めてReactがUIをハイドレートできます。
ReactとNext.jsを使用したSSRは、ユーザーにできるだけ早く非インタラクティブなページを表示することで、見た目の読み込みパフォーマンスを向上させます。


しかし、サーバー上でのすべてのデータ取得が完了するまでページをユーザーに表示できないため、依然として遅い場合があります。
ストリーミングは、ページのHTMLを小さなチャンクに分割し、それらのチャンクをサーバーからクライアントに段階的に送信することを可能にします。


これにより、すべてのデータが読み込まれるのを待たずに、ページの一部を早く表示できます。
ストリーミングはReactのコンポーネントモデルと相性が良く、各コンポーネントをチャンクと見なすことができます。優先度の高いコンポーネント(例:製品情報)やデータに依存しないコンポーネント(例:レイアウト)は最初に送信され、Reactはハイドレーションを早く開始できます。優先度の低いコンポーネント(例:レビュー、関連製品)は、データが取得された後に同じサーバーリクエストで送信できます。


ストリーミングは、長いデータリクエストがページのレンダリングを妨げるのを防ぎたい場合に特に有益であり、Time To First Byte (TTFB)やFirst Contentful Paint (FCP)を短縮できます。また、特に遅いデバイスでのTime to Interactive (TTI)の改善にも役立ちます。
例
<Suspense>
は、非同期アクション(例:データ取得)を実行するコンポーネントをラップし、その間にフォールバックUI(例:スケルトン、スピナー)を表示し、アクションが完了したらコンポーネントを入れ替えることで機能します。
- TypeScript
- JavaScript
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>
)
}
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を使用することで、以下の利点があります:
- ストリーミングサーバーレンダリング - サーバーからクライアントへのHTMLの段階的なレンダリング
- 選択的ハイドレーション - Reactはユーザーの操作に基づいて、どのコンポーネントを最初にインタラクティブにするかを優先します
より多くのSuspenseの例と使用例については、Reactのドキュメントを参照してください。
SEO
- Next.jsは、
generateMetadata
内でのデータ取得が完了するまで、UIをクライアントにストリーミングするのを待ちます。これにより、ストリーミングされたレスポンスの最初の部分に<head>
タグが含まれることが保証されます。 - ストリーミングはサーバーレンダリングされるため、SEOに影響しません。Googleのリッチリザルトテストツールを使用して、Googleのウェブクローラーにページがどのように表示されるかを確認し、シリアライズされたHTMLを表示できます(ソース)。
ステータスコード
ストリーミング時には、リクエストが成功したことを示すために200
ステータスコードが返されます。
サーバーは、ストリーミングされたコンテンツ内でクライアントにエラーや問題を伝えることができます。たとえば、redirect
やnotFound
を使用する場合です。レスポンスヘッダーはすでにクライアントに送信されているため、レスポンスのステータスコードを更新することはできません。これはSEOに影響しません。