Server Component とは何か
Server Component は、サーバー側だけで実行され、その JavaScript がブラウザに送られない React コンポーネントです。
#何が違うのか
これまでの React では、書いたコンポーネントは最終的にブラウザで動いていました。サーバーが HTML を先に作る構成(SSR)でも、同じコードがブラウザにも送られて、そこでもう一度動きます。
Server Component は違います。サーバーで一度動いて、結果だけを送ります。 そのコンポーネントの JavaScript はブラウザに届きません。
これまで コード ──▶ サーバーで実行 ──▶ HTML
コード ──────────────────▶ ブラウザでも実行
Server Component コード ──▶ サーバーで実行 ──▶ 結果だけ
(コードはブラウザに届かない)
#App Router ではこれが既定
app/ の下に書いたコンポーネントは、何も書かなければ Server Component です。Client Component にしたいときだけ、明示的に宣言します。
この既定が逆だと思っていると、ほぼすべての判断がずれます。まずここを押さえてください。
#できること
DB に直接アクセスできる
API を経由する必要がありません。
// app/products/page.tsx
export default async function Page() {
const items = await db.item.findMany()
return <List items={items} />
}
自分自身の API ルートを fetch で呼ぶ書き方をよく見かけますが、Server Component では遠回りです。サーバーの中にいるので、直接読めます。
秘密を扱える
API キーや DB の接続情報を、そのまま使えます。このコードはブラウザに届かないからです。
ただし渡した props はブラウザに届きます。ここが分かれ目です。
// これは安全(key はサーバーの中だけ)
const data = await fetch(url, { headers: { Authorization: key } })
// これは漏れる(key が props としてブラウザへ届く)
return <Panel apiKey={key} />
async にできる
コンポーネントそのものを async にして await できます。データ取得のために useEffect と状態を組む必要がありません。
#できないこと
| できないこと | 理由 |
|---|---|
useState useReducer | 状態はブラウザ側のもの |
useEffect | 描画後の副作用はブラウザ側のもの |
onClick などのイベント | 押すのはブラウザ |
window document | サーバーに存在しない |
localStorage | 同上 |
これらが必要になった時点で、その部分だけを Client Component に切り出します。
#何がブラウザに届くのか
Server Component が返した内容は、HTML と RSC ペイロードという形で送られます。コードではなく、描画の結果です。
つまり、
- 表示している値は届く(当然、画面に出るので)
- 表示していない値も、props として渡していれば届く
- コンポーネントの中で使っただけの変数は届かない
「画面に出ていないから安全」ではありません。境界を越えた props はすべて届きます。
#使い分けの目安
まず Server Component で書き始めて、ブラウザが必要になったところだけを切り出すのが基本です。
app/products/[id]/page.tsx Server(DB から商品を取得)
├─ ProductInfo Server(表示するだけ)
├─ ReviewList Server(表示するだけ)
└─ AddToCartButton Client(ここだけ)
逆に「とりあえず全部 Client にして、必要なら Server に戻す」という進め方は、送る JavaScript が増えるうえ、DB へ直接アクセスできる利点も失います。
#よくある誤解
SSR と同じもの?
違います。SSR は「同じコードをサーバーでも動かす」仕組みで、コードはブラウザにも送られます。Server Component はそもそもブラウザに送らない仕組みです。両方を同時に使うこともできます。
静的なページ専用?
違います。リクエストごとに実行することもできます。何をいつ実行するかは、Cookie や検索パラメータを読むかどうかなどで決まります。
遅くなる?
送る JavaScript が減るぶん、ブラウザ側の負担は軽くなります。ただしサーバー側の処理が遅ければページ全体が遅くなるので、そこは Suspense で分割します。