React 18 で本格化した React Server Components (RSC) は、サーバー側でデータ取得や重い処理を行い、クライアントに軽量な UI だけを送る仕組みです。初心者が最初に戸惑うポイントは「どこがサーバーコンポーネントで、どこがクライアントコンポーネントか」という境界です。
1. サーバーコンポーネントとクライアントコンポーネントの違い
| 特徴 | サーバーコンポーネント | クライアントコンポーネント |
|---|---|---|
| 実行場所 | Node.js(サーバー) | ブラウザ |
| 依存できる API |
fs, データベース, 外部 API など |
window, document, React hooks (useState, useEffect) |
| バンドルサイズ | 送られないので軽い | クライアントに送られるのでサイズに注意 |
2. 境界を明示する use client ディレクティブ
Next.js 13 以降、ファイル単位で境界を指定します。デフォルトはサーバーコンポーネントなので、クライアント側の機能が必要なときだけ次のように書きます。
// src/app/components/Counter.tsx
'use client'; // ← ここがクライアント境界
import { useState } from 'react';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(c => c + 1)}>
カウント: {count}
</button>
);
}
'use client' を書いたファイルは自動的にクライアントバンドルに含まれ、サーバー側では実行されません。
3. サーバーコンポーネントでデータ取得
サーバーコンポーネントは async 関数としてデータフェッチが可能です。以下は Supabase(BaaS)からユーザー一覧を取得する例です。
// src/app/components/UserList.tsx
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
export default async function UserList() {
const { data, error } = await supabase.from('users').select('id, name');
if (error) throw error;
return (
<ul>
{data.map(u => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}
このコンポーネントはサーバー上で実行され、取得した HTML がそのままクライアントに送られます。use client が無いので useState などは使えません。
4. CI / 自動デプロイと合わせて考える
RSC を活用した Next.js アプリは、GitHub Actions と Vercel(または Netlify)を組み合わせた自動デプロイが相性抜群です。プッシュすると以下の流れでデプロイが走ります。
-
npm ciで依存関係をインストール -
npm run buildでサーバーコンポーネントを含むビルドを実行 - ビルド成果物を Vercel にデプロイ
このパイプラインは、CI / 自動デプロイ のガイドに沿って設定すれば、初心者でも数分で本番環境に反映できます。
5. まとめ
- デフォルトはサーバーコンポーネント。クライアント側が必要なときだけ
'use client'を付ける - サーバーコンポーネントは
asyncでデータ取得が可能、BaaS と組み合わせやすい - CI と自動デプロイを設定すれば、コード変更が即座に本番に反映され、開発サイクルが高速化する
React Server Components の境界を正しく理解すれば、パフォーマンスの高いモダンな Web アプリが手軽に作れます。