モダンReact + Next.js #1 なぜNext.jsとServer Componentsなのか

読了 8分

React基礎講座(#1〜#15)Todoアプリビルドシリーズを終えられた方なら、クライアントサイドReactのほぼすべての基本は身についているはずです。今回のシリーズでは一段階上のレベルへ進んで、モダンReactの新しいパラダイム — Server Componentsと、それを最もうまく実現したフレームワークであるNext.jsを扱います。

全6編で構成されます。

  • #1 なぜNext.jsとServer Componentsなのか ← 今回の記事
  • #2 Next.jsの開始とApp Router
  • #3 Server Components vs Client Components
  • #4 データフェッチとキャッシング
  • #5 Suspenseとuse()によるローディング処理
  • #6 Server Actionsとフォーム

今回の記事はコードがほとんどありません。なぜ新しいモデルが必要なのか、それが何を解決するのかをまず明確にしておくことが、次の記事を理解するうえで決定的だからです。

CSR — 私たちがこれまでやってきた方式 #

これまで私たちが作ったすべてのReactアプリは、CSR(Client-Side Rendering)方式でした。

CSRの流れ
1. ブラウザが空のHTMLを受け取る (<div id="root"></div>だけがある殻)
2. JavaScriptバンドルをダウンロード
3. JavaScriptを実行 → Reactが画面を描画
4. 必要なら fetch でデータを取得 → 再描画

この方式の利点は明確です。

  • 一度ロードされた後のページ遷移が速い (#15で扱ったSPAの利点)
  • サーバーは静的ファイルだけホスティングすればよい (デプロイが単純)
  • インタラクションが豊富なUIの実装に強い

しかし、欠点も明確です。

欠点1. 最初の画面が遅く表示される #

ブラウザが空の画面を受け取り、JavaScriptをダウンロードし、実行して、ようやく画面が描画されます。インターネットが遅かったり、デバイスが弱かったりすると、白い画面が長時間表示されます。

欠点2. SEOが難しい #

検索エンジンのクローラーはJavaScriptを実行しないか、遅く実行します。空のHTMLだけでは本文をインデックスできず、検索表示が弱くなります。

欠点3. JavaScriptバンドルが大きくなる #

画面を描画するためのすべてのコード(コンポーネント、ライブラリ、データ処理ロジック)がクライアントにダウンロードされる必要があります。ライブラリを1つ追加するたびにユーザーが受け取る容量も大きくなります。

欠点4. データフェッチがウォーターフォール #

サーバー応答 → JSダウンロード → JS実行 → fetch → またfetch → … 段階ごとに待機時間が累積します。

SSR — サーバーでHTMLを事前に作る #

これらの問題を解決するために古くから使われてきた方式がSSR(Server-Side Rendering)です。PHPやRuby on Railsのような伝統的なWebサーバーモデルへの回帰ですね。

SSRの流れ
1. ブラウザがページをリクエスト
2. サーバーで React を実行してHTMLを生成
3. 完成したHTMLを送信 (コンテンツがすでに含まれている)
4. ブラウザがそのHTMLを表示
5. 同時にJSバンドルも受け取ってインタラクションを有効化 (hydration)

hydrationという単語が登場しましたが、「すでに描画された静的HTMLにJSでイベントハンドラを付けて、生きたコンポーネントにする」という意味です。乾いたHTMLにJSの水を注いで生かすという比喩から来ました。

SSRは最初の画面の速度とSEOの問題を解決してくれます。しかし、依然としてすべてのコンポーネントコードがクライアントに送信されてhydrationされる必要があるため、バンドルサイズの問題はそのまま残ります。

RSC — React Server Componentsの登場 #

ここでReactチームがさらに一歩進みます。「そもそもクライアントに送る必要のないコンポーネントもあるのではないか?」

ブログ記事の本文を考えてみてください。一度描画された後にユーザーがクリックしたり入力したりすることはほとんどありません。ただデータを取ってきて画面に出力するだけ。このようなコンポーネントなら、サーバーでのみ実行し、HTML(またはそれに近い表現)だけをクライアントに送ればよいわけです。コンポーネントのJavaScriptコード自体をクライアントに送る理由がありません。

これがReact Server Components(RSC)の核心アイデアです。

RSCの流れ
1. ブラウザがページをリクエスト
2. サーバーで Server Components を実行
3. Server Components はデータベース/API を直接呼び出し可能
4. 結果をシリアライズされた形式で送信 (HTML + クライアントコンポーネントの位置のみ表示)
5. クライアントは受け取ったHTMLを表示 + Client Components のみ hydrate

RSCが解決すること:

  • バンドルサイズ削減 — 静的なコンポーネントのコードはまったくクライアントに送られない
  • データフェッチが単純になる — Server Componentでただawait db.query(...)すればよい (ネットワーク往復なし)
  • 機密情報の保護 — APIキーやDB認証情報がクライアントに絶対に露出しない
  • SEOと最初の画面速度 — SSRの利点はそのまま

では、何がどこで実行されるのか #

このシリーズで何度も登場する核心概念です。頭の中に事前に描いておいてください。

コンポーネント種別実行場所使えるもの使えないもの
Server Componentsサーバーのみ (一度)DB直接アクセス、環境変数、fsモジュール、async/awaituseState、useEffect、イベントハンドラ、ブラウザAPI
Client Componentsサーバー(SSR) + クライアント(hydration)useState、useEffect、イベント、ブラウザAPIDB直接アクセス (セキュリティ)、fs

同じページの中で2種類が共存します。ページの静的なコンテンツ部分はServer Component、インタラクションが必要な部分(フォーム、トグル、ドロップダウンなど)はClient Componentで。この境界をうまく引くことがモダンReactアプリ設計の核心です。

Next.jsとの関係 #

React Server ComponentsはReact自体の機能ですが、これを実際に使うにはビルドツールとサーバーインフラが必要です。RSCをシリアライズし、ルーティングを処理し、キャッシングを管理し、サーバーを立ち上げる仕事を誰かがやってくれる必要があるからです。

Next.jsはReactチームと最も緊密に協業するメタフレームワークで、RSCを正式にサポートする最も成熟した選択肢です (RemixWakuのような他のオプションもありますが)。このシリーズではNext.jsを使います。

注記
このブログ(schoolofweb.net)自体もNext.jsで作られています。シリーズを読みながら「このサイトはどう動いているんだろう?」と気になっても良いですよ — Server Componentsで記事を取得し、クライアントでインタラクションが必要な部分だけをClient Componentsに分離した構造です。

メンタルモデル転換の核心 #

このシリーズを始める前に最も重要なマインドセット2つ:

1. 「このコードはどこで実行されるか?」を常に意識する #

これまで私たちは「コードはすべてブラウザで動く」という単一の環境で生きてきました。モダンReactでは、同じファイルの中でもサーバーで動くコードとクライアントで動くコードが混在することがあります。この境界を意識しないと急速に混乱します。

毎回自問してください。「この関数はサーバーで実行されるのか、クライアントで実行されるのか?」そうすれば、データフェッチがどう動くべきか、環境変数にアクセス可能か、イベントハンドラを付けても良いかが明確になります。

2. 基本はServer Component、必要なものだけClient Component #

新しいコンポーネントを作るとき、基本はServer Componentです (Next.js App Routerにおいて)。Client Componentが必要な明確な理由(状態、イベント、ブラウザAPI)があるときだけ、'use client'ディレクティブを付けて変換します。このデフォルトがバンドルサイズを小さく保つ核心です。

このシリーズで学べること #

次の記事から順に扱う内容です。

  • #2 Next.jsプロジェクトの開始、App Routerファイル構造、layoutシステム
  • #3 'use client'ディレクティブとサーバー/クライアントコンポーネントの境界
  • #4 Server Componentでのawait fetch(...)パターン、キャッシング
  • #5 Suspenseとloading.tsxuse()フックによるローディング処理
  • #6 Server Actionsによるフォーム送信とmutationの扱い

最後には小さなミニプロジェクト(メモのような単純なアプリ)ですべてを合わせてみます。

まとめ #

今回の記事ではなぜ新しいモデルが必要なのかをまず押さえました。

  • CSR — 速いインタラクション ✅、最初の画面が遅い / SEOが弱い / 大きなバンドル ❌
  • SSR — 最初の画面が速い / SEOが良い ✅、依然としてすべてのコードがクライアントに送信される ❌
  • RSC — 静的コンテンツはサーバーのみで実行され、コード自体がクライアントに送られない

頭の中に定着させるべき2つのマインドセット:

  1. 「このコードはどこで実行されるか?」を常に意識
  2. 基本はServer Component、必要なものだけClient Component

次の記事「モダンReact + Next.js #2 Next.jsの開始とApp Router」では、実際にNext.jsプロジェクトを作って、App Routerのファイルベースルーティングとlayoutシステムを直接触ってみましょう。

X