React Server Components - ServerとClientの境界を理解する

中級 | 8分 で読める | 2026.04.19

公式ドキュメント

React Server Componentsとは

React Server Components(RSC)は、ブラウザとは別の環境で先にrenderされるReact Componentです。build時に実行する構成と、requestごとにserverで実行する構成があります。

React 19では、Server Componentsを利用するアプリ向けの機能が安定しました。ただし、RSCをframeworkやbundlerへ組み込むための下位APIはsemverに従わず、React 19.xのminor updateでも変わる可能性があると公式ドキュメントに記載されています。

アプリ開発者は、RSCを自力でbundlerへ組み込むのではなく、Next.js App Routerなど対応frameworkを通して使うのが現実的です。

Server ComponentがServer側でDataへAccessし、転送できる値をClient Componentへ渡し、Browser側でState・Event・Browser APIを扱う境界図

Server ComponentsとSSRの違い

Server ComponentsとServer-Side Rendering(SSR)は同じではありません。

項目Server ComponentsSSR
主な目的Componentの一部をserver側だけで実行最初に表示するHTMLをserverで生成
browserへComponentコードを送るかServer Component自体は送らないhydrateするClient Componentのコードは送る
state・event handler利用できないhydrate後のClient Componentで利用
DBへの直接アクセスserver環境なら可能server処理内なら可能
組み合わせClient Componentsと組み合わせるRSCとも組み合わせられる

Next.js App Routerの初回表示では、RSC PayloadとClient Componentsを使ってHTMLも生成します。そのため、実際のframeworkではRSCとSSRが協調して動く場合があります。

Next.js App Routerでの基本

App Routerでは、pageとlayoutは標準でServer Componentsです。

import { getPost } from "@/lib/posts";

export default async function Page({
  params,
}: {
  params: Promise<{ id: string }>;
}) {
  const { id } = await params;
  const post = await getPost(id);

  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </article>
  );
}

Server Componentでは、server側のdata layerへ直接アクセスできます。API keyやDB passwordをbrowser bundleへ含めずに処理できます。

ただし、秘密情報を使えることと、認可が自動的に行われることは別です。利用者がそのデータを読めるか、server側で毎回確認します。

Client Componentが必要な処理

次の処理にはClient Componentを使います。

  • useStateなどのstate
  • clickやinputなどのevent handler
  • useEffect
  • windowlocalStorage、Geolocationなどbrowser API
  • client専用のcustom hook

ファイル先頭へ"use client"を追加すると、serverとclientのmodule graphの境界になります。

"use client";

import { useState } from "react";

export function LikeButton({ initial }: { initial: number }) {
  const [likes, setLikes] = useState(initial);

  return (
    <button onClick={() => setLikes((value) => value + 1)}>
      {likes} likes
    </button>
  );
}

"use client"を付けたfileがimportするmoduleもclient bundle側へ入ります。page全体へ付けるのではなく、操作が必要な小さな境界へ置くとserver側に残せる範囲が分かりやすくなります。

ServerからClientへ渡せる値

Server ComponentからClient Componentへ渡すpropsは、Reactが転送できる形式でなければなりません。

文字列、数値、boolean、plain object、配列などは扱えます。一方、DB connectionや任意のclass instance、browserへ送れないfunctionを通常のpropsとして渡すことはできません。

import { LikeButton } from "./like-button";

export default async function PostActions() {
  const post = await getPostSummary();

  return <LikeButton initial={post.likes} />;
}

Server Componentで取得したobject全体を無条件に渡すと、不要な個人情報や内部fieldをRSC Payloadへ含める可能性があります。Client Componentに必要な値だけを明示します。

"use server"の意味

Server Componentを表す"use server" directiveはありません。React公式も、この点をよくある誤解として説明しています。

"use server"は、Client側から呼び出せるServer Functionを定義するためのdirectiveです。form actionとして渡した場合はServer Actionと呼ばれます。

"use server";

export async function updateProfile(formData: FormData) {
  const user = await requireUser();
  const displayName = String(formData.get("displayName") ?? "");

  await saveProfile(user.id, { displayName });
}

Server Functionは公開されたserver endpointと同じように扱います。

  • 認証済み利用者を確認する
  • 操作対象への認可を確認する
  • inputをvalidationする
  • CSRFを含むframeworkのsecurity guidanceを確認する
  • errorへ秘密情報を含めない

Client Componentから呼べるからといって、安全な内部関数になるわけではありません。

StreamingとSuspense

Server Componentはasync functionにでき、render中にdataを待てます。時間のかかる部分をSuspense境界へ分けると、frameworkは準備できた部分から送信できます。

import { Suspense } from "react";

export default function Page() {
  return (
    <main>
      <h1>Dashboard</h1>
      <Suspense fallback={<p>読み込み中...</p>}>
        <RecentOrders />
      </Suspense>
    </main>
  );
}

Streamingを使えば必ず指標が一定割合改善するわけではありません。遅いquery、境界の位置、network、cacheによって結果は変わります。

導入時に確認すること

1. client boundaryを広げすぎない

"use client"を上位へ置くほど、client側へ含まれるmoduleが増えます。browser APIが必要なcomponentを切り出します。

2. requestごとの処理を把握する

DB queryや外部APIが、build時、request時、cache hit時のどこで実行されるかを確認します。RSCだけではcache方針は決まりません。

3. server-only dataを渡さない

環境変数、内部ID、権限情報をClient Componentのpropsやerror messageへ含めないようにします。

4. frameworkとReactの組み合わせを固定する

RSCのframework実装APIには互換性上の注意があります。frameworkが対応するReact versionを使い、独自にversionだけ上げない方が安全です。

5. production buildで検証する

development modeとproductionではrender、cache、bundleが異なる場合があります。build、start、実際のdeploy先まで確認します。

段階的に使う

既存のNext.js Pages Routerを一度にApp Routerへ移す必要はありません。URLが衝突しないようにしながら、独立性の高いrouteから移行できます。

  1. read-onlyなpageを選ぶ
  2. data取得をServer Componentへ移す
  3. 操作部分だけClient Componentにする
  4. loading・error boundaryを追加する
  5. 認証・認可・cacheを確認する
  6. bundleとWeb performanceを実測する

RSCの採用を目的にせず、serverでdataへ近づけたい、client JavaScriptを減らしたい、といった具体的な課題があるrouteから始めます。

まとめ

  • Server Componentsはbrowserとは別の環境で先にrenderされる
  • SSRとRSCは別の概念だが、framework内で組み合わせられる
  • stateやbrowser APIにはClient Componentを使う
  • "use server"はServer ComponentではなくServer Functionのdirective
  • 認証・認可・validation・cacheは別途設計する
  • 固定の性能改善率ではなく、自分のproduction buildで測定する

参考リソース

← 一覧に戻る
PR
PR
PR
PR