「あれ?どっちを使うべき?」Next.jsのServer ComponentsとServer Actionsを徹底解説
Next.jsのApp Routerで開発していると、「Server Components」と「Server Actions」という言葉をよく目にしませんか?
どちらもサーバーに関連する機能だけど、実際は何が違うの?いつどっちを使えばいいの?
この記事では、この2つの概念の違いを、分かりやすく解説します。
Server Componentsって結局何なの?
Server Componentsは、サーバー上でレンダリングされるReactコンポーネントです。App Routerでは、特に何も指定しなければ、すべてのコンポーネントはデフォルトでServer Componentsになります。
こんなメリットがあります
- 🔌 データベースに直接アクセスできる: わざわざAPIを経由する必要なし
- 🔒 APIキーなどの秘密情報を安全に扱える: クライアントに漏れる心配なし
コードで見るとこんな感じ
import { getUser } from '@/lib/db';
export default async function UserPage({ params }) {
// データベースに直接アクセス!クライアントからは見えない!
const user = await getUser(params.id);
return (
<div>
<h1>{user.name}さんのプロフィール</h1>
<p>メール: {user.email}</p>
</div>
);
}
シンプルですね。特別な指示子も必要なく、普通にコンポーネントを書けばOKです。
では、Server Actionsは?
一方、Server Actionsは、クライアントからサーバー上で実行できる非同期関数です。ユーザーがボタンをクリックしたり、フォームを送信したりしたときに、サーバー上で何かの処理をしたい場合に使います。
こんなメリットがあります
- 📝 フォーム送信が超簡単: わざわざAPIエンドポイントを作る必要なし
- 🔄 データの更新処理に最適: 作成・更新・削除などの操作がスムーズ
- 🧩 型安全: TypeScriptとの相性抜群
コードで見るとこんな感じ
'use server'; // この魔法の言葉が必要!
import { updateUser } from '@/lib/db';
import { revalidatePath } from 'next/cache';
export async function updateUserAction(formData: FormData) {
const name = formData.get('name') as string;
const email = formData.get('email') as string;
// サーバー上でデータベース更新!
await updateUser({ name, email });
// ページのキャッシュもさっと更新
revalidatePath('/users');
}
import { updateUserAction } from './actions';
export default function EditProfileForm() {
return (
<form action={updateUserAction}>
<input name="name" type="text" />
<input name="email" type="email" />
<button type="submit">更新</button>
</form>
);
}
'use server'
という指示子がポイントです。これがあることで、この関数はサーバー上で実行されることをNext.jsに伝えています。
一目でわかる違い
項目 | Server Components | Server Actions |
---|---|---|
役割 | 見せるためのもの | 変えるためのもの |
実行タイミング | ページを開いた時 | ユーザーが何かしたとき |
合言葉 | なし(デフォルト) | 'use server' |
よく使うシーン | データ取得 → 表示 | フォーム送信、データ更新 |
呼び出し方 | <Component /> |
action={myAction} |
どっちを使うべき?
Server Componentsを選ぶのはこんなとき
-
👀 データを表示するだけのとき
- 「ユーザー情報を表示したい」
- 「商品一覧を見せたい」
-
💾 データベースから直接データを読み取りたいとき
- 「DBから最新の投稿を取得して表示したい」
Server Actionsを選ぶのはこんなとき
-
📝 フォームを送信するとき
- 「ユーザー登録フォーム」
- 「お問い合わせフォーム」
-
✏️ データを変更するとき
- 「いいねボタンを押したらカウントを増やしたい」
- 「コメントを投稿したらDBに保存したい」
-
🔄 ページ内容を更新したいとき
- 「フィルターを変更したら商品一覧を更新したい」
実際の開発ではこう使い分ける!
「ユーザープロフィール編集ページ」を例に見てみましょう。
import { getUser } from '@/lib/db';
import ProfileForm from './profile-form';
export default async function ProfilePage({ params }) {
// Server Componentでデータを取得
const user = await getUser(params.id);
return (
<div>
<h1>{user.name}さんのプロフィール</h1>
{/* 取得したデータをフォームの初期値として渡す */}
<ProfileForm user={user} />
</div>
);
}
'use server';
import { updateUser } from '@/lib/db';
import { revalidatePath } from 'next/cache';
export async function updateProfileAction(userId: string, formData: FormData) {
const name = formData.get('name') as string;
const bio = formData.get('bio') as string;
// Server Actionでデータを更新
await updateUser(userId, { name, bio });
// 更新後はページを再検証
revalidatePath(`/profile/${userId}`);
}
'use client';
import { updateProfileAction } from './actions';
export default function ProfileForm({ user }) {
return (
<form action={formData => updateProfileAction(user.id, formData)}>
<div>
<label htmlFor="name">名前</label>
<input id="name" name="name" defaultValue={user.name} />
</div>
<div>
<label htmlFor="bio">自己紹介</label>
<textarea id="bio" name="bio" defaultValue={user.bio} />
</div>
<button type="submit">更新する</button>
</form>
);
}
この例では、
- Server Componentでユーザーデータを取得して表示
- フォームを通じてServer Actionを呼び出してデータを更新
- 更新後にページを再検証して最新の状態を表示
という流れで、それぞれの長所を活かしています。
まとめ
- 見せることが目的なら → Server Components
- 変えることが目的なら → Server Actions
両方をうまく組み合わせることで、高速で開発効率の良いアプリケーションが構築できます。Next.jsのApp Routerの真価を発揮するには、この2つを適材適所で使い分けることがポイントです。