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キーなどの秘密情報を安全に扱える: クライアントに漏れる心配なし

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

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との相性抜群

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

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');
}
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に保存したい」
  • 🔄 ページ内容を更新したいとき

    • 「フィルターを変更したら商品一覧を更新したい」

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

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

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>
  );
}
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}`);
}
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つを適材適所で使い分けることがポイントです。

参考リンク

Discussion