5.1 なぜ Server Components が生まれたか
Part 3 と Part 4 で見てきた React は、ブラウザの中で動く SPA(Single Page Application)の形でした。最初の HTML はほぼ空で、JavaScript を読み込んでから画面を描き始める、というやり方です。これはこれで柔軟な仕組みなのですが、アプリの規模が大きくなってくると、ちょっと困ったことがいくつか顔を出してきます。Server Components(以降 RSC)は、その困りごとをまた別の角度から片付けるための仕組みだと思ってください。
この章では RSC の仕様そのものよりも、まず 「なぜ必要になったのか」 の方を先に押さえておきます。API の具体的な使い方は 5.2 Server vs Client、5.3 Next.js App Router で扱います。
5.1.1 SPA で起きる 4 つの困りごと
SPA というスタイルを選んだ時点で、ほぼ自動的についてくる問題がいくつかあります。一つずつ見ていきましょう。
(1) 初回表示までの時間
SPA では、ブラウザが次のステップを順番にこなす必要があります。
- HTML を受け取る(中身はほぼ空)
- JavaScript バンドルをダウンロードする
- JavaScript を parse / compile する
- React が実行され、コンポーネントをレンダーする
fetchでデータを取りに行く- 受け取ったデータで再レンダーして、ようやく画面が埋まる
ユーザーが「内容が読める」 状態になるまでに踏む段数が多く、バンドルが大きくなるほど各段階の時間が積み重なっていきます。
(2) クライアントに届く JavaScript の量
SPA では、画面を作るために必要なコードは 全部クライアントに届きます。Markdown レンダラーやシンタックスハイライトのような「重いけれど 1 回表示するためだけに使うライブラリ」も、すべてユーザーのブラウザにダウンロードされます。その結果、通信量もメモリも増えてしまいます。
(3) SEO と SNS プレビュー
SPA では最初の HTML がほぼ空なので、検索エンジンや SNS のクローラーは「まだ中身がない」 状態の HTML を読むことになります。クローラーが JavaScript を実行してくれるケースもあるにはあるのですが、挙動はクローラーごとにまちまちです。サーバー側で HTML を組み立ててから返す方が、中身は確実に伝わります。
(4) データ取得のウォーターフォール
SPA ではコンポーネントがレンダーされて初めて useEffect の中で fetch が走ります。親が先に読まれ、親の結果を使って子がさらに次を読む、という形になると ネットワーク通信が直列につながっていく ことになります。
図 5.1.1 SPA のデータ取得ウォーターフォール
縦方向の段数がそのまま、ユーザーの待ち時間に変わっていきます。
図 5.1.2 SPA と RSC の表示パイプライン比較
SPA と RSC では、「最初の表示が画面に出るまで」 のパイプラインがずいぶん違います。時間軸で並べると、違いがより見やすくなります。
5.1.2 RSC のアイデア
RSC は、上の問題に対して「コンポーネントの 一部 をサーバーで実行して、その結果だけをブラウザに送る」 という切り口で答えを出します。
react.dev では次のように説明されています。
Server Components are a new type of Component that renders ahead of time, before bundling, in an environment separate from your client app or SSR server.(react.dev / Server Components)
ポイントは バンドルされる前に、 しかも 別の環境で レンダーされる、というところです。従来の SSR(Server-Side Rendering)が「同じコンポーネントをサーバーで 1 回、クライアントでもう 1 回実行する」 ものだったのに対し、Server Components は そもそもクライアントでは動かない コンポーネントを用意する、という発想です。
整理すると、コンポーネントは次の 2 種類に分かれます。
| 種類 | 走る場所 | バンドルに含まれる? |
|---|---|---|
| Server Component | サーバー(ビルド時 or リクエスト時) | 含まれない |
| Client Component | サーバー(初回 HTML)+ ブラウザ | 含まれる |
Server Component は、最終的に「レンダー済みの結果」 だけがブラウザに届きます。コンポーネントのロジックや、ロジックが使っていたライブラリ(たとえば Markdown パーサー)は、クライアントのバンドルには一切入りません。
図 5.1.3 Server Component が返すもの
Client Component のコードは、これまで通りブラウザに届きます。違うのは「Server Component の実装と、その依存ライブラリは送らない」 という点です。
5.1.3 Server Component で何ができるか
サーバー側で実行される以上、サーバー側のリソースを直に使えます。react.dev から引くと、Server Component は次のようなことができます。
- データベースやファイルシステムに直接アクセスする
- CMS や API からデータを取る
- 秘密情報(API キー・認証トークン)を扱う
- 重いライブラリをサーバー側でだけ使って、結果を返す
これらは クライアントにコードが届かない ので、セキュリティとバンドルサイズの両方に効いてきます。
逆に、Server Component でできないこともあります。
useStateやuseEffectなどの「クライアント用フック」onClickのようなイベントハンドラwindowやdocumentなどのブラウザ API
これらは実行される場所が「ブラウザ」 のものなので、サーバーでは意味を持ちません。インタラクションが要る部分は、Client Component として分けて書くことになります。境界の設計は 5.2 で詳しく扱います。
5.1.4 React 19 と RSC の関係
react.dev/blog/2024/12/05/react-19 には次のような記述があります。
React 19 includes all of the React Server Components features included from the Canary channel.
つまり RSC は React 19 で 安定版に入った 機能です。ただし同じ記事には、RSC を実装するためのフレームワーク向け API はセマンティックバージョニングに従わない可能性がある、という注意書きもあります。
While React Server Components in React 19 are stable and will not break between minor versions, the underlying APIs used to implement a React Server Components bundler or framework do not follow semver and may break between minors in React 19.x.
この「フレームワーク向けには動く可能性がある」 という線引きは大事なポイントです。アプリケーション開発者が直接 RSC のランタイム API を触ることはありません。代わりにフレームワーク(代表は Next.js App Router)が RSC の仕組みを組み込んでくれていて、開発者は「この page.tsx は Server Component」「ここから下は Client Component」 という形で使っていきます。
RSC を実用するための主要な選択肢は、次の通りです。
| フレームワーク | 方針 |
|---|---|
| Next.js App Router | app/ 以下が RSC ベース。この Part の後続章で扱います |
| Waku | 最小構成で RSC を体験できる |
本サイトでは Next.js App Router を基準にしていきますが、RSC そのものは React 側の概念なので、他のフレームワークでも用語はおおむね共通です。
5.1.5 RSC を使うと何が変わるか
最後に、冒頭で挙げた「SPA の 4 つの困りごと」 が RSC だとどう扱われるかを並べておきます。
| 困りごと | RSC の扱い |
|---|---|
| 初回表示が遅い | 初期 HTML に内容が入った状態で届く(JS ダウンロード前に読める) |
| バンドルが大きい | Server Component とその依存はバンドルに入らない |
| SEO / SNS | サーバーが HTML を組み立てるため、クローラーが読める |
| ウォーターフォール | データ取得がサーバー側で閉じるため、ブラウザ ↔ API の往復が減る |
逆に、RSC が 苦手な こともあります。
- 画面の大半がユーザー操作で動的に変わる UI(ダッシュボード、リアルタイムエディタなど)は、従来通り Client Component 中心で書く方が自然です
- サーバーを持たない完全静的サイトで、ビルド時に全部書き出す運用で済むなら、 SPA でも十分です
「とにかく RSC にすれば速い」 というものではなく、「画面のどこが静的に決まり、どこがユーザー操作で変わるか」 を切り分ける設計が必要になります。次の章では、その切り分け方を具体的に見ていきましょう。