サーバ゙ーコンポーネント

React サーバーコンポーネントを使用すると、サーバ゙ーでレンダリングされ、オプションでキャッシュ可能な UI を記述できます。Next.js では、レンダリング作業がルートセグメントごとに分割され、ストリーミングと部分的なレンダリングが可能になります。また、3つの異なるサーバーレンダリング戦略があります:

このページでは、サーバーコンポーネントの動作方法、使用するタイミング、およびさまざまなサーバーレンダリング戦略について説明します。

サーバーレンダリングの利点

サーバーでレンダリング作業を行うことには、次のような利点があります:

  • データフェッチ (Data Fetching): サーバーコンポーネントを使用すると、データフェッチをサーバーに移動し、データソースに近づけることができます。これにより、レンダリングに必要なデータの取得時間とクライアントが行う必要のあるリクエストの量を減らすことでパフォーマンスが向上します。
  • セキュリティ (Security): サーバーコンポーネントを使用すると、トークンやAPIキーなどの機密データやロジックをクライアントに公開するリスクなくサーバー上に保持できます。
  • キャッシュ (Caching): サーバーでレンダリングすることで、結果をキャッシュし、後続のリクエストやユーザー間で再利用できます。これにより、各リクエストで行われるレンダリングとデータフェッチの量を減らすことで、パフォーマンスが向上し、コストが削減されます。
  • バンドルサイズ (Bundle Sizes): サーバ゙ーコンポーネントを使用すると、以前はクライアントの JavaScript バンドルサイズに影響を与えていた大規模な依存関係をサーバー上に保持できます。これは、インターネット接続が遅いユーザーや性能の低いデバイスにとって有益です。クライアントはサーバーコンポーネントの JavaScript をダウンロード、解析、実行する必要がないためです。
  • 初期ページロードと First Contentful Paint (FCP): サーバー上で HTML を生成することで、クライアントがページをレンダリングするために必要な JavaScript をダウンロード、解析、実行するのを待たずに、ユーザーがすぐにページを表示できるようにします。
  • 検索エンジン最適化 (SEO) とソーシャルネットワーク共有性: レンダリングされた HTML は、検索エンジンのボットがページをインデックスしたり、ソーシャルネットワークのボットがページのソーシャルカードプレビューを生成するために使用できます。
  • ストリーミング (Streaming): サーバーコンポーネントを使用すると、レンダリング作業をチャンクに分割し、準備ができ次第クライアントにストリーミングできます。これにより、ユーザーはサーバーでページ全体がレンダリングされるのを待たずに、ページの一部をすぐに確認できます。

Next.js でのサーバーコンポーネントの使用

Next.js ではデフォルトでサーバーコンポーネントが使用されます。これにより、追加の設定なしで自動的にサーバーレンダリングを実装できます。必要に応じてクライアントコンポーネントを使用することもできます。詳細は クライアントコンポーネント を参照してください。

サーバーコンポーネントのレンダリング方法

サーバー上では、Next.js は React の API を使用してレンダリングを調整します。レンダリング作業は、個々のルートセグメントと Suspense 境界 (Suspense Boundaries) によってチャンクに分割されます。

各チャンクは2つのステップでレンダリングされます:

  1. React はサーバーコンポーネントを React サーバーコンポーネントペイロード (RSC Payload) と呼ばれる特別なデータ形式にレンダリングします。
  2. Next.js は RSC ペイロードとクライアントコンポーネントの JavaScript 命令を使用して、サーバー上で HTML をレンダリングします。

次に、クライアント側では:

  1. HTML は、ルートの非インタラクティブなプレビューをすぐに表示するために使用されます - これは初期ページロードのみのためです。
  2. React サーバーコンポーネントペイロードは、クライアントとサーバーコンポーネントツリーを調整し、DOM を更新するために使用されます。
  3. JavaScript 命令は、クライアントコンポーネントを ハイドレート (hydrate) し、アプリケーションをインタラクティブにするために使用されます。

React サーバーコンポーネントペイロード (RSC) とは?

RSC ペイロードは、レンダリングされた React サーバーコンポーネントツリーのコンパクトなバイナリ表現です。React がクライアントでブラウザの DOM を更新するために使用します。RSC ペイロードには以下が含まれます:

  • サーバーコンポーネントのレンダリング結果
  • クライアントコンポーネントをレンダリングする場所のプレースホルダーとそれらの JavaScript ファイルへの参照
  • サーバーコンポーネントからクライアントコンポーネントに渡されるプロパティ

サーバーレンダリング戦略

サーバーレンダリングには、静的、動的、ストリーミングの3つのサブセットがあります。

静的レンダリング (デフォルト)

静的レンダリングでは、ルートは ビルド時 または データの再検証 (data revalidation) 後にバックグラウンドでレンダリングされます。結果はキャッシュされ、コンテンツデリバリーネットワーク (CDN) にプッシュできます。この最適化により、レンダリング作業の結果をユーザー間やサーバーリクエスト間で共有できます。

静的レンダリングは、ユーザーごとにパーソナライズされていないデータやビルド時に既知のデータを持つルート(静的ブログ投稿や商品ページなど)に有用です。

動的レンダリング

動的レンダリングでは、ルートは各ユーザーに対して リクエスト時 にレンダリングされます。

動的レンダリングは、ユーザーごとにパーソナライズされたデータや、クッキーやURLの検索パラメータなど、リクエスト時にしかわからない情報を持つルートに有用です。

キャッシュされたデータを持つ動的ルート

ほとんどのウェブサイトでは、ルートは完全に静的でも完全に動的でもありません - それは連続体です。例えば、一定間隔で再検証されるキャッシュされた商品データを使用するが、キャッシュされていないパーソナライズされた顧客データも持つeコマースページがあるかもしれません。

Next.js では、キャッシュされたデータとキャッシュされていないデータの両方を持つ動的にレンダリングされたルートを持つことができます。これは、RSC ペイロードとデータが別々にキャッシュされるためです。これにより、リクエスト時にすべてのデータを取得することによるパフォーマンスへの影響を心配することなく、動的レンダリングを選択できます。

フルルートキャッシュ (full-route cache)データキャッシュ (Data Cache) について詳しく学びます。

動的レンダリングへの切り替え

レンダリング中に 動的関数 (dynamic functions) または キャッシュされていないデータリクエスト (uncached data request) が検出されると、Next.js はルート全体を動的にレンダリングするように切り替えます。この表は、動的関数とデータキャッシュがルートの静的または動的レンダリングにどのように影響するかをまとめたものです:

動的関数データルート
なしキャッシュ済静的レンダリング
ありキャッシュ済動的レンダリング
なしキャッシュなし動的レンダリング
ありキャッシュなし動的レンダリング

上記の表で、ルートが完全に静的であるためには、すべてのデータがキャッシュされている必要があります。ただし、キャッシュされたデータフェッチとキャッシュされていないデータフェッチの両方を使用する動的にレンダリングされたルートを持つことができます。

開発者として、静的レンダリングと動的レンダリングのどちらかを選択する必要はありません。Next.js は使用される機能とAPIに基づいて、各ルートに最適なレンダリング戦略を自動的に選択します。代わりに、特定のデータをキャッシュまたは再検証するタイミング を選択し、UIの一部を ストリーミング することを選択できます。

動的関数

動的関数は、ユーザーのクッキー、現在のリクエストヘッダー、URLの検索パラメータなど、リクエスト時にしかわからない情報に依存します。Next.js では、これらの動的関数は:

  • cookies()headers(): サーバーコンポーネントでこれらを使用すると、ルート全体がリクエスト時に動的レンダリングに切り替わります。
  • useSearchParams():
    • クライアントコンポーネントでは、静的レンダリングをスキップし、代わりに最も近い親の Suspense 境界までのすべてのクライアントコンポーネントをクライアント側でレンダリングします。
    • useSearchParams() を使用するクライアントコンポーネントを <Suspense/> 境界でラップすることを推奨します。これにより、その上のクライアントコンポーネントを静的にレンダリングできます。
  • searchParams: ページ (Pages) プロップを使用すると、ページはリクエスト時に動的レンダリングに切り替わります。

これらの関数のいずれかを使用すると、ルート全体がリクエスト時に動的レンダリングに切り替わります。

ストリーミング

ストリーミング中のルートセグメントの並列化を示す図。個々のチャンクのデータフェッチ、レンダリング、ハイドレーションを示しています。

ストリーミングにより、サーバーからUIを段階的にレンダリングできます。作業はチャンクに分割され、準備ができ次第クライアントにストリーミングされます。これにより、ユーザーはコンテンツ全体のレンダリングが完了する前に、ページの一部をすぐに確認できます。

クライアント側で部分的にレンダリングされたページを示す図。ストリーミング中のチャンクのローディングUIが表示されています。

ストリーミングは Next.js の App Router にデフォルトで組み込まれています。これは、初期ページの読み込みパフォーマンスと、ルート全体のレンダリングをブロックする遅いデータフェッチに依存するUIの両方を改善するのに役立ちます。例えば、商品ページのレビューなどです。

loading.jsReact Suspense を使用して、ルートセグメントのストリーミングを開始できます。詳細については、ローディングUIとストリーミング セクションを参照してください。