Loading UI and Streaming
特別なファイル loading.js
は、React Suspense を使用して意味のある LoadingUI を作成するのに役立ちます。この規約により、route セグメントの内容がロードされている間に、server から瞬時の loading 状態を表示できます。新しいコンテンツは、レンダリングが完了すると自動的に入れ替えられます。
Instant Loading States
インスタントの loading 状態は、ナビゲーション時にすぐに表示される fallback UI です。スケルトンやスピナーなどの loading インジケーターを事前にレンダリングしたり、カバーフォトやタイトルなど、未来の画面の小さなが有意義な部分を表示したりすることができます。これにより、ユーザーは app が応答していることを理解し、ユーザー体験が向上します。
フォルダ内に loading.js
ファイルを追加することで、loading 状態を作成します。
export default function Loading() {
// You can add any UI inside Loading, including a Skeleton.
return <LoadingSkeleton />
}
export default function Loading() {
// You can add any UI inside Loading, including a Skeleton.
return <LoadingSkeleton />
}
同じフォルダ内に、loading.js
は layout.js
の中にネストされます。それは自動的に page.js
ファイルとその下の children を <Suspense>
境界でラップします。
Good to know:
- ナビゲーションは即時で、server-centric routing を使用してもです。
- ナビゲーションは中断可能で、つまり routes を変更する際に、その route のコンテンツが全てロードされるまで待つ必要はなく、別の route へのナビゲーションが可能です。
- 共有 Layout は新しい route セグメントがロードされる間もインタラクティブ性を保持します。
推奨事項: route (layout やページ)のセグメントに
loading.js
を使用する事をお勧めします。なぜなら、 Next.js はこの機能を最適化しているからです。
Streaming with Suspense
loading.js
に加えて、自分の UI Component 用に手動で Suspense 境界線を作成することもできます。App Router は、Suspense を用いた Streaming を Node.js と Edge runtimes の両方でサポートしています。
Streaming とは何ですか?
React と Next.js での Streaming の動作を理解するためには、Server-Side Rendering( SSR ) とその制限を理解することが役立ちます。
SSR を使用すると、ユーザーがページを見て操作する前に完了させる必要がある一連の手順があります:
- まず、指定されたページのすべてのデータは、server で取得されます。
- その後、server はページの HTML をレンダリングします。
- そのページの HTML、CSS、そして JavaScript は、client に送信されます。
- 生成された HTML と CSS を使用して、非対話型のユーザーインターフェースが表示されます。
- 最終的に、React はユーザーインターフェースを hydrates して対話型にします。
これらのステップは順次的で、 blocking つまり、 server はすべてのデータが取得されるまでページの HTML を render することしかできません。また、 client 上では、 React はページ内のすべてのコンポーネントの code がダウンロードされるまで UI を適用することしかできません。
SSR は、React および Next.js と一緒に使用すると、非対話型のページを可能な限り早くユーザーに表示することで、 perceived loading パフォーマンスを向上させるのに役立ちます。
しかし、すべてのデータの取得が server 上で完了するまで、ページがユーザーに表示されるのは依然として遅い可能性があります。
ストリーミングは、ページの HTML を小さなチャンクに分割し、それらのチャンクを徐々に server から client に送信することを可能にします。
これにより、ページの一部がより早く表示され、全てのデータがロードされるのを待たずに UI をレンダリングすることができます。
ストリーミングは React の component モデルと非常に相性が良いです。それぞれの component は一つの塊と考えることができます。 priority が高い component(例えば製品情報)、またはデータに依存しない component(例えば layout)は、最初に送信され、React は早期に hydration を開始できます。 priority が低い component(例えばレビュー、関連製品)は、データを取得した後に同じ server request で送信することができます。
ストリーミングは、Time To First Byte (TTFB) や First Contentful Paint (FCP) を減らすことで、長時間のデータリクエストが blocking ページのレンダリングを防ぐ場合に特に有益です。また、特に低速なデバイスでは Time to Interactive (TTI) の改善にも役立ちます。
Example
<Suspense>
は、非同期アクション(例:fetch データ)を実行する component をラップし、それが起こっている間に fallback UI(例:スケルトン、スピナー)を表示し、アクションが完了すると、あなたの component に切り替える働きをします。
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 を使用することで、次のような利点が得られます:
- ストリーミング Server レンダリング - server から client に対して徐々に HTML をレンダリングします。
- 選択的なハイドレーション - React はユーザーのインタラクションに基づいて最初にどのコンポーネントをインタラクティブにするかを選択します。
さらに多くの Suspense の例や使用例をご覧になりたい方は、React ドキュメンテーション を参照してください。
SEO
- Next.js は、
generateMetadata
内のデータフェッチングが完了するのを待ってから、client に UI を Streaming します。これにより、Streaming される response の最初の部分が<head>
タグを含むことが保証されます。 - Streaming は server でレンダリングされるため、SEO に影響を与えません。Google の Rich Results Test ツールを使用して、Google の Web クローラーにどのようにページが表示され、シリアライズされた HTML(source ) を確認することができます。
ステータス Code
Streaming 時には、request が成功したことを示すために 200
のステータス code が返されます。
server は Streaming されたコンテンツ自体の中で、例えば、redirect
や notFound
を使用するときなど、client に対して error や問題をまだ伝えることができます。既に response headers は client に送信されているため、response のステータス code を更新することはできません。これは SEO に影響を与えません。