Next.jsのServer ComponentsとServer Actionsを徹底解説

# 「あれ？どっちを使うべき？」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キーなどの秘密情報を安全に扱える**: クライアントに漏れる心配なし

### コードで見るとこんな感じ

```tsx:app/page.tsx(Server Component)
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との相性抜群

### コードで見るとこんな感じ

```tsx:app/actions.ts(Server Action)
'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');
}
```

```tsx:app/edit-profile.tsx
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に保存したい」

- 🔄 **ページ内容を更新**したいとき
  - 「フィルターを変更したら商品一覧を更新したい」

## 実際の開発ではこう使い分ける！

「ユーザープロフィール編集ページ」を例に見てみましょう。

```tsx:app/profile/[id]/page.tsx(Server Component)
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>
  );
}
```

```tsx:app/profile/[id]/actions.ts(Server Action)

'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}`);
}
```

```tsx: app/profile/[id]/profile-form.tsx(Client Component)
'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>
  );
}
```

この例では、

1. **Server Component**でユーザーデータを取得して表示
2. フォームを通じて**Server Action**を呼び出してデータを更新
3. 更新後にページを再検証して最新の状態を表示

という流れで、それぞれの長所を活かしています。

## まとめ

- **見せる**ことが目的なら → **Server Components**
- **変える**ことが目的なら → **Server Actions**

両方をうまく組み合わせることで、高速で開発効率の良いアプリケーションが構築できます。Next.jsのApp Routerの真価を発揮するには、この2つを適材適所で使い分けることがポイントです。



## 参考リンク

- [Next.js公式ドキュメント: Server Components](https://nextjs.org/docs/app/building-your-application/rendering/server-components)
- [Next.js公式ドキュメント: Server Actions](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions)