Bỏ qua tới nội dung
Quay lại danh sách bài viết
Developer Tools15分

React Server Components trong Next.js 16 ở môi trường sản xuất: Bài học thực tiễn

React Server Components 2026 in Production: Rebuilding with Next.js 16 PPR and use cache

今井 理香Principal Frontend Engineer
2026-04-2015分
ReactNext.jsRSCPPRStreamingPerformance

Bài viết này được đăng bằng tiếng Nhật. Tóm tắt tiếng Việt ở dưới:

React Server Components trong Next.js 16 ở môi trường sản xuất: Bài học thực tiễnTriển khai React Server Components trong Next.js 16 sản xuất thực tế: ranh giới Server/Client Component, chiến lược streaming, quản lý cache và các anti-pattern phổ biến cần tránh.

RSCが「議論」から「既定値」になった2026年

React Server Components(RSC)は2023年の登場当初、SPAを組み慣れたチームからは強い抵抗を受けた技術だった。「hydrationが複雑になる」「デバッグが困難」「ストリーミングが本当に速いのか誰も測っていない」——そんな批判が2024年を通じて渦巻いていたのは記憶に新しい。だが2026年4月現在、状況は一変した。Next.js 16の安定版リリースでPartial Prerendering(PPR)が既定で有効となり、use cache ディレクティブが React 公式として採用され、RSCはもはや「新機能」ではなく「default」になった。

筆者のチームでは2025年後半から2026年第1四半期にかけて、月間3,000万PVの ECサイトを Pages Router + SWR の構成から Next.js 16 の App Router + RSC へ段階的に移行した。本稿ではその現場で実測した数値、設計判断、そしてハマった穴を共有する。結論から言えば JavaScript bundle は 62% 削減、Core Web Vitals の LCP は p75 で 2.8s → 1.4s に改善したが、道中は決して平坦ではなかった。

PPR: 静的と動的の境界を Suspense で刻む

Partial Prerendering は従来の SSG と SSR の二者択一を打ち砕く発想で、ひとつのルート内に静的シェルと動的ホールを同居させる。静的シェルは build 時に HTML としてプリレンダリングされ CDN エッジから即座に返る。動的な部分だけが Suspense 境界で区切られ、リクエスト時に RSC ペイロードとしてストリームされる。ユーザー体験上は「最初の 40ms で画面の骨格が出て、パーソナライズ部分だけが後から挿し込まれる」動作になる。

実装上の鍵は experimental.ppr: 'incremental' から始める点だ。ルートごとに export const experimental_ppr = true を宣言した場所だけが PPR 対象になるため、既存の動的ルートを壊さずに段階導入できる。我々は最初に商品一覧ページ、次にカート、最後にマイページと移行した。マイページのように認証必須のページでも、ヘッダー・フッター・推薦枠だけを静的シェルに落とし、ユーザー固有部分を <Suspense> で包めば PPR が効く。

ハマりどころは Suspense 境界の粒度だ。最初は「とりあえず動的部分を一括で Suspense で囲む」実装をしたが、これでは結局ページ全体のストリーミングが遅い箇所に律速されてしまう。正解は独立してフェッチできる単位ごとに境界を切ること。具体的には商品詳細ページで「在庫状況」「レビュー」「関連商品」「パーソナライズ推薦」の4箇所をそれぞれ Suspense で包んだところ、TTFB は変わらないまま LCP が 600ms 改善した。

use cache: メモ化の新しい語彙

React 19.2 と Next.js 16 で正式採用された use cache ディレクティブは、関数やコンポーネントの結果をサーバー側でメモ化する宣言的な仕組みだ。従来の unstable_cache や fetch のキャッシュオプションと異なり、関数の引数とクロージャ変数を自動的にキャッシュキーとして取り扱う点が革新的で、人間がキーを組み立てる必要がない。

```typescript async function getProduct(id: string) { 'use cache'; cacheLife('hours'); cacheTag(`product-${id}`); const res = await fetch(`${API}/products/${id}`); return res.json(); } ```

cacheLife でデフォルトの再検証間隔を宣言し、cacheTag で後述する on-demand 無効化のタグを付ける。重要なのは use cache がコンポーネントにも使えることだ。JSX を返す async 関数にディレクティブを付ければレンダリング結果そのものがキャッシュされる。これにより、従来 getStaticProps + revalidate で書いていたパターンが格段にローカルで完結するようになった。

cache tags と on-demand 無効化の運用

ECサイトで最大の悩みは「在庫が動いたら即座に商品ページを再生成したい」という要件だ。Next.js 16 ではこれを revalidateTag が担う。管理画面から在庫更新 API を叩いた後に revalidateTag(`product-${id}`) を呼べば、タグに紐づくすべてのキャッシュエントリが失効する。

運用上の注意は タグの粒度設計 に尽きる。初期実装で我々は "products" のような粗いタグを全商品ページに貼ってしまい、1商品の価格変更で 50万ページが一斉に revalidate される事故を起こした。CDN オリジンに瞬間的に 10,000 rps が流れ込み、オリジン側の DB コネクションプールが枯渇した。教訓は「タグは可能な限り細かく」「複数のスコープを必要とするなら複数タグを併用」だ。現在の我々のルールは、商品ページには `product-${id}`、`category-${categoryId}`、`brand-${brandId}` の3階層を必ず付与し、用途に応じて使い分ける。

移行ハマリどころ 5選

第1に `"use client"` 境界の判定が難しい。初期には「フックを使うから」「onClick があるから」という理由で無思考に client にしていたが、これは bundle 肥大化の最大要因だ。正解は「can it be server?」を先に問うこと。データ取得・データ変換・JSX 生成はすべて server で可能で、本当に必要なのはブラウザ API とインタラクティブイベントだけだ。

第2に Context の越境。Server Component から Client Component へ props で値を渡すのは簡単だが、その逆は不可能である。認証情報など横断的な値を Client に運ぶには、Server 側で Context Provider Wrapper を作り、その中に Client Component を配置する必要がある。

第3に third-party ライブラリの互換性。2025年までは多くの UI ライブラリが "use client" を欠いていたが、2026年には MUI v7、Chakra v4、Mantine v8 がすべて RSC 対応済みだ。ただし date-fns や lodash の tree-shaking は「named import を使う」「barrel ファイルを避ける」の徹底が必要で、これを怠ると bundle が倍になる。

第4に 動的インポートの再設計。next/dynamic の ssr: false は依然として使えるが、RSC 世界では server component なら bundle に入らないため、動的インポートの必要性自体が激減する。我々は 120箇所あった next/dynamic を 18箇所まで削減した。

実測値: bundle と Core Web Vitals

移行前後の First Load JS の中央値は 318KB → 121KB へ落ちた。商品詳細ページは 412KB → 89KB と劇的に軽量化した。商品データ整形・構造化データ生成・関連商品アルゴリズムがすべて server 側に移り、client には「カートに入れる」「画像ギャラリー」だけが残った結果だ。

Core Web Vitals は LCP p75 が 2.8s → 1.4s、INP p75 が 280ms → 140ms、CLS は 0.08 → 0.03。Lighthouse Performance スコアは 72 → 94、CrUX 実測でも「Good」判定割合が 58% → 89% に上昇した。SEO の副次効果として Google Search Console の「インデックス登録済み」率が 6 ポイント上がった。

まとめ: RSC は思想を学び直す価値がある

RSC は単なる描画モード切替ではなく、「どこで何を計算するか」というアーキテクチャの設計言語を書き換える技術だ。Next.js 16 の PPR と use cache が加わった今、RSC はようやく本番投入に耐える成熟度に達した。移行コストは決して小さくないが、bundle 削減、パフォーマンス改善、そして長期的なメンテナビリティの観点で投資対効果は高い。新規プロジェクトなら迷わず RSC + App Router から始めるべき時代になったと言って良いだろう。

Cùng giải quyết các thách thức kỹ thuật của bạn.

KGA IT Solutions có đội ngũ chuyên gia AI, cloud và DevOps mang lại giải pháp tối ưu cho thách thức của bạn.

Liên hệ