はじめに
Reactを使い始めると「CSR」「SSR」「SSG」といった略語をよく目にします。これらはすべてレンダリング手法、つまり「画面をどうやって表示するか」の方法です。
どの手法を選ぶかで、ページの表示速度やSEO(Search Engine Optimization:検索エンジン最適化)対策、サーバーの負荷が大きく変わります。この記事では、Reactの基本的な仕組みと各レンダリング手法の違いを整理した上で、実際にNext.jsでどう使い分けるかまでを解説します。
Reactとは
Reactは、Meta(旧Facebook)が開発したUI(User Interface:ユーザーが操作する画面)を構築するためのJavaScriptライブラリです。2013年にオープンソースとして公開されました。
Reactには大きく3つの特徴があります。
コンポーネントベース
UIを「コンポーネント」という部品に分けて作ります。ボタン、ヘッダー、フォームなど、それぞれ独立した部品として開発し、組み合わせてページを構成します。
// ボタンコンポーネントの例
function Button({ label, onClick }) {
return <button onClick={onClick}>{label}</button>;
}
// コンポーネントを組み合わせてページを作る
function App() {
return (
<div>
<Header />
<Button label="送信" onClick={() => alert('送信しました')} />
<Footer />
</div>
);
}
宣言的UI
「どういう状態のときに、どういう見た目にするか」を記述するスタイルです。状態が変わると、Reactが自動的に画面を更新してくれます。
function Counter() {
const [count, setCount] = useState(0);
// countの値に応じたUIを「宣言」するだけ
// DOMの操作はReactが自動で行う
return (
<div>
<p>カウント: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
仮想DOM
Reactの内部で使われている仕組みで、画面更新を高速に行うための技術です。次の章で詳しく説明します。
仮想DOMの仕組み ― Reactの心臓部
通常のDOM操作の問題
ブラウザが管理するDOM(Document Object Model)は、HTMLの構造をツリー状に表現したものです。
たとえば、以下のようなHTMLがあるとします。
<html>
<body>
<header>
<h1>サイト名</h1>
</header>
<main>
<p>こんにちは</p>
<button>クリック</button>
</main>
</body>
</html>
ブラウザはこれを次のようなツリー構造(DOM)として管理しています。
html
│
body
┌──┴──┐
header main
│ ┌──┴──┐
h1 p button
│ │ │
"サイト名" "こんにちは" "クリック"
JavaScriptから直接このDOMを操作すると、ブラウザは レイアウトの再計算や再描画 を行います。この処理はコストが高く、変更が多いとページの動作が遅くなります。
仮想DOMによる解決
Reactは、実際のDOMのコピーをメモリ上に軽量なJavaScriptオブジェクトとして保持しています。これが 仮想DOM です。
画面更新は以下の2段階で行われます。
1. レンダーフェーズ
状態が変わると、Reactは新しい仮想DOMを作成し、変更前の仮想DOMと比較します。この比較処理を 差分検出(Reconciliation) と呼びます。
2. コミットフェーズ
差分が見つかった部分だけを、実際のDOMに反映します。変更がなければDOMには何もしません。
状態変更 → 新しい仮想DOMを作成 → 前回の仮想DOMと比較(差分検出)
→ 差分があった箇所だけ実際のDOMを更新
こうすることで無駄なDOM操作が減り、画面の更新が速くなります。
レンダリング手法の全体像
Reactが仮想DOMで画面を効率的に更新することはわかりました。では「どこで・いつHTMLを作るか」はどう決まるのでしょうか?
この「どこで・いつ」の違いがレンダリング手法の違いです。Reactのエコシステムには、用途に応じていくつかのレンダリング手法があります。
| 手法 | 正式名称 | ひとことで言うと |
|---|---|---|
| CSR | Client-Side Rendering | ブラウザ上でHTMLを組み立てる |
| SSR | Server-Side Rendering | アクセスのたびにサーバーでHTMLを生成する |
| SSG | Static Site Generation | ビルド時にHTMLを事前に作っておく |
| ISR | Incremental Static Regeneration | 事前生成したHTMLを定期的に更新する |
| RSC | React Server Components | コンポーネント単位でサーバー/ブラウザを使い分ける |
| Streaming SSR | Streaming Server-Side Rendering | 準備できた部分から順にHTMLを送る |
| PPR | Partial Prerendering | 1ページ内で静的部分と動的部分を共存させる |
それぞれ得意な場面が違うので、ここからひとつずつ見ていきます。
先に知っておきたい用語:JSバンドル
この先「JavaScriptバンドル(JSバンドル)」という言葉が何度か出てきます。
Reactアプリは、たくさんのJavaScriptファイルに分かれて開発します。しかしブラウザにファイルを100個も200個も送ると、通信回数が増えて遅くなります。そこで、ビルド時にこれらのファイルを1つ(または少数)のファイルにまとめる処理を行います。この「まとめられたJavaScriptファイル」がJSバンドルです。
【開発時】 【ビルド後】
src/App.jsx ─┐
src/Header.jsx │
src/Button.jsx ├─→ バンドル → bundle.js(1ファイルにまとまる)
src/utils.js │
node_modules/react ─┘
JSバンドルのサイズが大きいほど、ブラウザのダウンロードと実行に時間がかかり、ページの表示が遅くなります。各レンダリング手法は、このJSバンドルを「どこで・どれだけ使うか」がそれぞれ異なります。
CSR(Client-Side Rendering)
概要
CSRはReactのデフォルトのレンダリング方式で、ブラウザ(クライアント)側でJavaScriptを実行してHTMLを組み立てます。
処理の流れ
1. ブラウザがサーバーにリクエスト
2. サーバーはほぼ空のHTMLとJavaScriptファイルを返す
3. ブラウザがJavaScriptをダウンロード・実行
4. ReactがDOMを構築して画面を表示
5. ユーザーが操作可能になる
メリット
- サーバーの負荷が低い(HTMLの生成をブラウザに任せるため)
- ページ遷移が高速(SPA=Single Page Applicationとして動作し、ページ全体を再読み込みしない)
- インタラクティブなUIに向いている
デメリット
- 初期表示が遅い(すべてのJSバンドルをダウンロード・実行してからHTMLを組み立てるため)
- SEOに弱い(検索エンジンのクローラー(Webページを自動で巡回して情報を収集するプログラム)がJavaScriptを実行できない場合、コンテンツを認識できない)
- JavaScriptが無効な環境では何も表示されない
向いているケース
管理画面、ダッシュボード、ログイン後のアプリなど、SEOが不要でユーザー操作が多いアプリケーション。
SSR(Server-Side Rendering)
概要
SSRでは、ユーザーがページにアクセスするたびにサーバー側でHTMLを生成して返します。ブラウザには完成したHTMLが届くので、初期表示が速くなります。
処理の流れ
1. ブラウザがサーバーにリクエスト
2. サーバーがReactコンポーネントを実行してHTMLを生成
3. 完成したHTMLをブラウザに返す → ユーザーは画面を見られる
4. JavaScriptをダウンロード
5. ハイドレーション(HTMLにイベントリスナーを紐づけて操作可能にする)
ハイドレーションとは
SSRで返されたHTMLは見た目だけの静的なページです。ボタンをクリックしても何も起きません。HTMLとは別に、JSバンドルもブラウザに送られます。このJSが読み込まれた後にハイドレーションという処理が走ります。
ハイドレーションは、サーバーが生成したHTMLに対してReactがイベントリスナー(クリックや入力に反応する処理の登録)を紐づける作業です。イメージとしては、「見た目だけの張りぼてに、動く仕組みを後から注入する」ような処理です。これが完了して初めて、ページがインタラクティブになります。
CSRとの違いは、JSバンドルの役割です。CSRではHTMLの組み立てから操作の処理まですべてをJSが担いますが、SSRではHTMLはサーバーが作成済みなので、JSは操作を動かすためだけに使われます。
メリット
- 初期表示が速い(HTMLが完成した状態で届く)
- SEOに強い(検索エンジンがHTMLの内容をそのまま読める)
- コンテンツが常に最新(リクエストのたびに生成するため)
デメリット
- リクエストのたびにサーバーでHTMLを生成するため、サーバー負荷が高い
- TTFB(Time to First Byte:最初の1バイトが届くまでの時間)がCSRより遅くなりがち
- HTML生成が完了するまでデータを返せないため
- ハイドレーション完了まで操作できない時間がある
向いているケース
ニュースサイト、ECサイトの商品ページなど、SEOが重要でコンテンツが頻繁に更新されるページ。
SSG(Static Site Generation)
概要
SSGは、ビルド時にあらかじめHTMLを生成しておく方式です。アクセスがあったら、生成済みのHTMLファイルをそのまま返します。
処理の流れ
【ビルド時】
1. すべてのページのHTMLを事前に生成
2. CDN(Content Delivery Network:世界中に分散配置された配信サーバー)に配置
【ユーザーアクセス時】
1. CDNから事前生成済みのHTMLを返す → 非常に高速
2. JSバンドルもダウンロード(ハイドレーション用)
3. ハイドレーションでページが操作可能になる
SSRと同様に、HTMLとは別にJSバンドルもブラウザに送られます。HTMLの生成タイミングが「ビルド時」なだけで、ハイドレーションの仕組みはSSRと同じです。
メリット
- 表示が非常に速い(CDNからの配信で、サーバー処理が不要)
- サーバーコストが低い(静的ファイルの配信だけで済む)
- SEOに強い
- セキュリティリスクが低い(サーバー処理がない)
デメリット
- コンテンツを更新するには再ビルドが必要
- ページ数が多いとビルド時間が長くなる
- リアルタイムなデータを扱えない
向いているケース
ブログ、ドキュメントサイト、ポートフォリオなど、更新頻度が低い静的コンテンツ。
ISR(Incremental Static Regeneration)
概要
ISRは、SSGの弱点だった「更新のたびに全ページを再ビルドする」問題を解決する方式です。個々のページを一定間隔で再生成する仕組みで、Next.jsが導入しました。
JSバンドルの扱いはSSGと同じで、HTMLと一緒にブラウザへ送られ、ハイドレーションに使われます。
処理の流れ
【初回アクセス】
1. ビルド時に生成されたHTMLを返す(SSGと同じ)
【設定した有効期限(例: 60秒)が過ぎた後のアクセス】
1. まず古いキャッシュ(一時保存)済みのHTMLを即座に返す(ユーザーを待たせない)
2. 裏側でサーバーがページを再生成して、キャッシュを新しいHTMLに差し替える
3. 次にアクセスした人からは、更新されたHTMLが返される
つまり「60秒以内のアクセスはキャッシュをそのまま返す → 60秒を過ぎたら裏で再生成」という動きです。
設定例(Next.js Pages Router):
// pages/blog.jsx ← このファイルが /blog ページになる
export default function BlogPage({ posts }) {
// ここが画面に表示される部分
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
// ↓ この関数をページファイル内に書くと、Next.jsがビルド時に実行する
export async function getStaticProps() {
const posts = await fetchPosts(); // API(Application Programming Interface:外部サービスとデータをやり取りする窓口)やDBからデータ取得
return {
props: { posts }, // 上のコンポーネントにpropsとして渡される
revalidate: 60, // 60秒ごとにこのページを再生成する(これがISRの設定)
};
}
ポイントは revalidate: 60 の部分です。この1行を追加するだけで、SSGからISRに切り替わります。
メリット
- SSGと同等の高速な表示
- 全ページの再ビルドが不要(変更があったページだけ更新)
- 最新データをある程度反映できる
デメリット
- リアルタイム性はない(再検証間隔分のタイムラグがある)
- Next.jsなどの対応フレームワークが必要
向いているケース
ECサイトの商品一覧、ブログの記事一覧など、定期的に更新されるが即時反映は不要なコンテンツ。
RSC(React Server Components)
概要
React Server Components(RSC)は、React 19で安定版として導入された新しいコンポーネントの仕組みです。コンポーネント単位でサーバーとクライアントの役割を分けられます。
これまでのSSRが「ページ全体をサーバーで生成する」のに対し、RSCは「このコンポーネントはサーバーで、このコンポーネントはクライアントで」と細かく指定できる点が異なります。
Server ComponentとClient Component
RSCでは、コンポーネントを2種類に分けて使います。
-
Server Component: サーバーでのみ実行される。JSをブラウザに送らないので軽量だが、
useStateやクリックイベントなどのユーザー操作は扱えない。データの取得や表示に向いている -
Client Component: サーバーで初期HTMLが生成された後、ブラウザでハイドレーションされて動く。従来のReactコンポーネントと同じで、
useStateやイベント処理が使える。ファイルの先頭に"use client"と書いて宣言する
Next.js(App Router)では、何も宣言しなければServer Componentになります。Client Componentにしたいときだけ"use client"を書きます。
// Server Component(何も書かなければデフォルトでこちらになる)
async function ArticleList() {
const articles = await db.query('SELECT * FROM articles');
return (
<ul>
{articles.map(a => (
<li key={a.id}>
<ArticleTitle title={a.title} />
</li>
))}
</ul>
);
}
// Client Component
// "use client" を宣言するとブラウザで動作する
"use client";
function ArticleTitle({ title }) {
const [liked, setLiked] = useState(false);
return (
<div>
<span>{title}</span>
<button onClick={() => setLiked(!liked)}>
{liked ? '♥' : '♡'}
</button>
</div>
);
}
SSRとの違い
| 項目 | SSR | RSC |
|---|---|---|
| レンダリング単位 | ページ全体 | コンポーネント単位 |
| JSバンドル | 全コンポーネント分を送信 | Client Componentのみ送信 |
| データ取得 | getServerSideProps等で一括 | 各Server Componentで個別に |
| 状態管理 | クライアントで管理 | Server Componentでは使えない |
メリット
- JavaScriptバンドルサイズの大幅削減(Server Componentのコードはブラウザに送られない。SSRやSSGではハイドレーション用に全コンポーネント分のJSを送っていたが、RSCではClient Componentの分だけで済む)
- サーバー上でデータベースに直接アクセスできる
- 通常のReactではブラウザからAPI経由でデータを取得しますが、Server Componentはサーバーで実行されるため、APIを挟まずにデータベースへ直接問い合わせ(クエリ)を投げられます
- 大きなライブラリ(マークダウンパーサーなど)をサーバー側だけで使える
- サーバーでしか使わないライブラリはJSバンドルに含まれないため、ブラウザに送るファイルサイズが増えません
デメリット
- Server Componentでは
useStateやuseEffectが使えない - 学習コストがある(どちらのコンポーネントにすべきか判断が必要)
- Next.jsなどの対応フレームワークが必要
向いているケース
データ表示が中心のページ、パフォーマンスを重視するアプリケーション。
Streaming SSR と Selective Hydration
Streaming SSR
従来のSSRでは、ページ全体のHTMLが完成するまでブラウザには何も返せませんでした。レストランで「全品揃ってから提供する」ようなイメージです。Streaming SSRでは、準備できたコンポーネントから順にHTMLを送信します。「できた料理から先に出す」方式です。
// Suspense(データ取得中の代替表示を定義するコンポーネント)でストリーミング境界を定義
function Page() {
return (
<div>
<Header /> {/* すぐにHTMLとして送信 */}
<Suspense fallback={<p>記事を読み込み中...</p>}>
<ArticleContent /> {/* 準備できたら送信 */}
</Suspense>
<Suspense fallback={<p>コメントを読み込み中...</p>}>
<Comments /> {/* 準備できたら送信 */}
</Suspense>
</div>
);
}
遅いAPIからのデータ取得がある場合でも、他の部分は先にユーザーに表示されます。
Selective Hydration
React 18以降では、ハイドレーションもコンポーネント単位で段階的に実行されるようになりました。ページ全体のハイドレーションを待たなくても、準備できた箇所から操作を受け付けられます。
ユーザーが触ろうとしたコンポーネントを優先的にハイドレーションする仕組みも備わっています。
PPR(Partial Prerendering) ― 次世代のレンダリング
概要
PPR(Partial Prerendering)は、Next.js 15で実験的に導入されたレンダリング手法です。1つのページの中で静的な部分と動的な部分を共存させます。
従来は「このページはSSG」「このページはSSR」とページ単位で選ぶ必要がありました。PPRでは、ページ内のコンポーネントごとに静的・動的を使い分けます。
処理の流れ
【ビルド時】
静的な部分(ヘッダー、サイドバー等)のHTMLを事前生成
動的な部分はSuspenseのfallbackを配置
【ユーザーアクセス時】
1. 静的なシェル(外枠)をCDNから即座に返す
2. 動的な部分はサーバーでストリーミング生成
3. 準備できた箇所からfallbackと差し替え
メリット
- 静的部分はCDN配信で超高速
- 動的部分も同じページ内でリアルタイムに表示
- SSGとSSRの良いとこ取り
現状
Next.js 15で実験的に導入され、Next.js 16(2025年10月リリース)では設定方法がcacheComponentsに変更されました。まだ発展途上の機能であり、今後も仕様が変わる可能性があります。
レンダリング手法の比較
| 手法 | レンダリング場所 | タイミング | 初期表示 | SEO | データの鮮度 | 代表的な用途 |
|---|---|---|---|---|---|---|
| CSR | ブラウザ | アクセス時 | 遅い | 弱い | リアルタイム | 管理画面、SPA |
| SSR | サーバー | アクセス時 | 速い | 強い | リアルタイム | ECサイト、ニュース |
| SSG | サーバー | ビルド時 | 非常に速い | 強い | ビルド時点 | ブログ、ドキュメント |
| ISR | サーバー | ビルド時+定期更新 | 非常に速い | 強い | 準リアルタイム | 商品一覧、記事一覧 |
| RSC | サーバー+ブラウザ | アクセス時 | 速い | 強い | リアルタイム | データ表示中心のアプリ |
| PPR | サーバー+CDN | ビルド時+アクセス時 | 非常に速い | 強い | 部分的にリアルタイム | ハイブリッドなページ |
Reactは「ライブラリ」であり「フレームワーク」ではない
ここまでCSR、SSR、SSGなどのレンダリング手法を見てきましたが、ReactはあくまでUIライブラリです。「ライブラリ」は必要な機能を自分で選んで組み合わせる部品集で、「フレームワーク」はアプリの作り方の枠組みごと提供してくれるセットです。Reactはライブラリなので、画面の部品(コンポーネント)を作って表示する機能だけを提供しています。
【Reactが担当すること】
・コンポーネント(UIの部品を作る)
・仮想DOM(画面を効率的に更新する)
・Hooks(useState, useEffect など状態管理)
【Reactが担当しないこと】
・ルーティング(URLに応じてページを切り替える)
・SSR / SSG / ISR(サーバー側でHTMLを生成する)
・データの取得方法(APIとの通信の仕組み)
・ファイル構成のルール
React単体だと、レンダリング方式はCSR(ブラウザ上でHTMLを組み立てる)しかできません。この記事で紹介したSSRやSSG、ISRなどを使うには、Reactベースのフレームワークが必要です。
Reactベースの主なフレームワーク
Reactの足りない部分を補い、すぐにアプリ開発を始められるようにしたのがフレームワークです。React公式もフレームワークの利用を推奨しています。
| フレームワーク | 特徴 | 対応するレンダリング手法 | 向いている用途 |
|---|---|---|---|
| React単体(Vite等) | ビルドツールのみ | CSR | 管理画面、学習用 |
| Next.js | 最も普及。Vercel社が開発 | CSR, SSR, SSG, ISR, RSC, PPR | 本格的なWebアプリ |
| React Router(旧Remix) | Web標準を重視。2024年末にRemixから統合 | CSR, SSR | シンプルな構成 |
| Gatsby | 静的サイト生成に特化 | SSG | ブログ、ドキュメント |
App RouterとPages Router
ここからは、最も普及しているNext.jsに絞って具体的な使い方を見ていきます。
Next.jsには2つのルーティング方式があります。
| Pages Router | App Router | |
|---|---|---|
| 登場時期 | Next.js初期から | Next.js 13(2023年〜) |
| ディレクトリ | pages/ |
app/ |
| ページの定義 | ファイル名がURLになる(pages/about.jsx → /about) |
フォルダ + page.tsxがURLになる(app/about/page.tsx → /about) |
| デフォルトの動作 | 全コンポーネントがクライアントで動く(useState等が使える) |
全コンポーネントがServer Componentになる(useState等は使えない) |
| RSC対応 | ✕ | ○ |
| Streaming SSR | ✕ | ○ |
| PPR | ✕ | ○(実験的) |
各レンダリング手法の環境対応
前半で紹介したレンダリング手法が、React単体・Pages Router・App Routerのどこで使えるかをまとめると以下のようになります。
| 手法 | React単体 | Pages Router | App Router |
|---|---|---|---|
| CSR | ○ | ○ | ○ |
| SSR | △ | ○ | ○ |
| SSG | ✕ | ○ | ○ |
| ISR | ✕ | ○ | ○ |
| RSC | △ | ✕ | ○ |
| Streaming SSR | △ | ✕ | ○ |
| PPR | ✕ | ✕ | ○ |
○=対応 △=技術的には可能だが現実的ではない ✕=非対応
Pages Routerのレンダリング切り替え
Pages Routerでは、ページファイルにどの関数を書くかで、レンダリング手法が自動的に決まります。
pages/blog.jsx に...
何も書かない → SSG(データなし。書いたJSX(JavaScriptの中にHTMLのような記法で書けるReactの構文)がそのままHTMLになる)
getStaticProps を書く → SSG(ビルド時にAPIやDBからデータを取得してHTMLに組み込む)
getStaticProps + revalidate → ISR(定期的に再生成)
getServerSideProps を書く → SSR(アクセスのたびにデータ取得)
next/dynamicに{ ssr: false } → CSR(サーバーでのHTML生成をスキップ)
getServerSidePropsとgetStaticPropsは、Next.jsが認識する決まった名前の関数です。ページファイル内でこの名前でexport(外部に公開)すると、Next.jsが自動的に検出してサーバー側で実行し、その結果をコンポーネントにprops(引数)として渡してくれます。設定ファイルを変える必要はなく、関数を書くだけでレンダリング手法が切り替わります。
// 【SSG】getStaticPropsを書く → ビルド時に1回だけ実行される
export async function getStaticProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return { props: { posts } };
}
// 【ISR】getStaticPropsにrevalidateを追加 → ビルド時+定期的に再実行される
export async function getStaticProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return {
props: { posts },
revalidate: 60, // この1行を追加するだけでSSGからISRに切り替わる
};
}
// 【SSR】getServerSidePropsを書く → アクセスのたびにサーバーで実行される
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return { props: { posts } };
}
※ これらの関数はページファイル内に1つだけ書きます(getServerSidePropsとgetStaticPropsの併用はできません)。
App Routerのレンダリング切り替え
App Routerでは、getServerSidePropsのような専用関数は使いません。コンポーネント内で何を使うかによって、レンダリング手法が自動的に決まります。
何もしない → SSG(静的レンダリング)
cookies()やheaders()を使う → SSR(リクエストごとに生成)
export const revalidate = 60 → ISR(定期再生成)
"use client"を書く → Client Component(ブラウザで動くコンポーネント)
Suspenseでコンポーネントを囲む → Streaming SSR
next/dynamicに{ ssr: false }を指定 → CSR(ブラウザだけで描画)
cacheComponents設定 + Suspense → PPR(実験的機能)
Pages RouterのgetServerSidePropsなどとは違い、App Routerではコンポーネント内で何を使うかによって自動的にレンダリング手法が決まります。それぞれの具体的な使い方を見ていきます。
SSG(何もしない → デフォルトで静的レンダリング)
App Routerでは、動的なAPIを使わなければデフォルトでSSGになります。Server Componentの中で直接await fetch()やデータベースクエリを書けるため、getStaticPropsのような専用関数は不要です。
// app/blog/page.jsx — 何も指定しなければSSG
export default async function BlogPage() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
return (
<ul>
{posts.map(post => <li key={post.id}>{post.title}</li>)}
</ul>
);
}
SSR(動的なAPIを使う → リクエストごとに生成)
cookies()、headers()、searchParamsなどのリクエスト情報を取得する関数を使うと、自動的にSSRに切り替わります。export const dynamic = 'force-dynamic'で明示的にSSRにすることもできます。
// app/dashboard/page.jsx — cookies()を使うので自動的にSSR
import { cookies } from 'next/headers';
export default async function Dashboard() {
const token = (await cookies()).get('session');
const data = await fetch('https://api.example.com/user', {
headers: { Authorization: `Bearer ${token.value}` },
}).then(r => r.json());
return <div>{data.name}さんのダッシュボード</div>;
}
ISR(revalidateを設定 → 定期再生成)
export const revalidate = 60をページに書くか、fetchのオプションで設定します。
// app/news/page.jsx — 60秒ごとに再生成
export const revalidate = 60;
export default async function NewsPage() {
const news = await fetch('https://api.example.com/news').then(r => r.json());
return <ul>{news.map(n => <li key={n.id}>{n.title}</li>)}</ul>;
}
RSC(Server ComponentとClient Component)
App Routerでは何も書かなければServer Componentになります。useStateやクリックイベントが必要なコンポーネントだけ、ファイルの先頭に"use client"を書いてClient Componentにします。
// Server Component(デフォルト)— JSがブラウザに送られないので軽量
export default async function ArticleList() {
const articles = await db.query('SELECT * FROM articles');
return <ul>{articles.map(a => <li key={a.id}>{a.title}</li>)}</ul>;
}
// Client Component — "use client"を書くとuseStateなどが使える
"use client";
export default function LikeButton() {
const [liked, setLiked] = useState(false);
return <button onClick={() => setLiked(!liked)}>{liked ? '♥' : '♡'}</button>;
}
Streaming SSR(Suspenseで囲む → 準備できた部分から送信)
<Suspense>でコンポーネントを囲むと、そのコンポーネントのデータ取得完了を待たずに、他の部分を先にブラウザへ送信します。loading.tsxファイルを作る方法でも実現できます。
// app/article/page.jsx
import { Suspense } from 'react';
export default function ArticlePage() {
return (
<div>
<h1>記事ページ</h1>
<Suspense fallback={<p>コメントを読み込み中...</p>}>
<Comments /> {/* データ取得に時間がかかっても他の部分は先に表示される */}
</Suspense>
</div>
);
}
CSR(next/dynamicでssr: false → ブラウザだけで描画)
サーバーでのHTML生成を完全にスキップして、ブラウザだけで描画したい場合に使います。"use client"だけではCSRにはなりません(サーバーでも初期HTMLが生成されます)。
// app/chart/page.jsx
"use client";
import dynamic from 'next/dynamic';
// { ssr: false }でサーバーでの描画をスキップ
const Chart = dynamic(() => import('./ChartComponent'), { ssr: false });
export default function ChartPage() {
return <Chart />;
}
PPR(実験的機能 — 静的部分と動的部分を1ページ内で共存)
静的部分はビルド時に生成され、<Suspense>で囲んだ動的部分だけがアクセス時にストリーミング生成されます。
Next.js 15ではexperimental_pprで有効化していましたが、Next.js 16ではcacheComponentsに変更されました。
// next.config.ts(Next.js 16)
import type { NextConfig } from 'next';
const nextConfig: NextConfig = { cacheComponents: true };
export default nextConfig;
// app/product/page.tsx
import { Suspense } from 'react';
export default function ProductPage() {
return (
<div>
<StaticHeader /> {/* ビルド時にHTMLが生成される */}
<Suspense fallback={<p>価格を取得中...</p>}>
<DynamicPrice /> {/* アクセス時にストリーミング生成 */}
</Suspense>
</div>
);
}
現在のNext.js公式はApp Routerを推奨していますが、Pages Routerも引き続きサポートされています。
まとめ
Reactのレンダリング手法は、CSRから始まり、SSR、SSG、ISR、RSC、PPRへと広がってきました。
選び方の目安:
- SEOが不要なアプリ → CSR
- SEOが必要で、データが頻繁に変わる → SSR
- 更新頻度が低い静的コンテンツ → SSG
- 静的コンテンツだが定期更新したい → ISR
- JSバンドルを減らしたい、データ取得が多い → RSC
- 1ページ内に静的と動的が混在する → PPR
大事なのは、これらは排他的な選択肢ではないという点です。Next.jsでは、ページやコンポーネントごとに手法を組み合わせて使えます。
まずはCSRとSSRの違いをつかむところから始めて、プロジェクトに合った手法を選んでいくのがおすすめです。