発行:

Server Actions (データ更新)

前章では、サーバー側の処理(バックエンド)を行う手段としてAPI Route を学びました。クライアント側(ブラウザ)からこのバックエンドAPIを fetch などのメソッドを用いてリクエストするのが一般的な方法でした。
しかし、Next.js の Server Actions を使うと、 API を作らずに、コンポーネントから直接サーバー側の関数を呼び出す ことができます。

Server Actions とは?

関数の中に "use server" と書くだけで、その関数がサーバー上で実行されるようになります。
これにより、クライアント(ブラウザ)の JavaScript が減り、コードも直感的になります。

仕組みと推奨される理由

「関数をインポートして実行しているだけ」に見えますが、実際の 裏側では POST リクエストが送信されています
Next.js は、ビルド時に Server Action の関数ごとに独自の URL エンドポイントを生成し、クライアントから呼び出された際に、Next.js 独自のプロトコルを使って通信を行っています。(ネットワークタブを見ると、特殊なヘッダーやペイロードが確認できます)

なぜこれが推奨されるのか? (BFFアーキテクチャ)

Server Actions は、 BFF (Backend For Frontend) の思想を体現した機能だからです。

  • フロントエンドのためのバックエンド : 画面に必要な処理だけを、画面のコードのすぐ近く(または同じファイル)に書くことができます。
  • セキュア : コンポーネントから直接呼んでいますが、処理自体はサーバー内でのみ実行されるため、データベースの認証情報などがブラウザに漏れることはありません。
  • API定義の手間削減 : REST API の設計やドキュメント作成の手間を省き、UI の開発スピードを最大化できます。

基本的な使い方(フォーム送信)

簡単な「Todo追加」の例で見てみましょう。

1. Server Action の定義

通常は actions.ts などの別ファイルに定義するのが管理しやすいです。

src/app/actions.ts
"use server"; // ファイルの先頭に書くと、中身はすべてServer Actionになる

import { revalidatePath } from "next/cache";

// サーバー上で実行される関数
export async function addTodo(formData: FormData) {
  // フォームから値を取得
  const title = formData.get("title")?.toString();

  if (!title) return;

  // ここで本来はデータベースに保存する
  console.log("Saving todo:", title);
  
  // キャッシュを更新して画面をリフレッシュ(重要!)
  revalidatePath("/");
}

2. コンポーネントから呼び出し

form タグの action 属性に、インポートした関数を渡すだけです。

src/app/page.tsx
import { addTodo } from "./actions";

export default function Page() {
  return (
    <main className="p-4">
      <h1>Todo App</h1>
      
      {/* action属性に関数を直接渡す */}
      <form action={addTodo} className="flex gap-2">
        <input 
          name="title" 
          type="text" 
          className="border p-2" 
          placeholder="新しいタスク"
        />
        <button type="submit" className="bg-blue-500 text-white p-2">
          追加
        </button>
      </form>
    </main>
  );
}

これだけで、ボタンを押すと裏側でサーバーへのRPC(リモートプロシージャコール)が発生し、addTodo 関数が実行されます。fetchuseState も使っていません。非常にシンプルですね!

クライアントコンポーネントからの呼び出し

ボタンにクリックイベント (onClick) をつけて Server Action を呼び出したい場合は、コンポーネント側を "use client" にする必要がありますが、呼び出し方は同じです。

"use client";
import { addTodo } from "./actions";

export default function ClientButton() {
  return (
    <button onClick={async () => await addTodo(/* ... */)}>
      追加
    </button>
  );
}

※ フォームの場合は action 属性を使う方がプログレッシブエンハンスメント(JS無効でも動く)の観点で推奨されます。

まとめ

Server Actions は、Next.js App Router 時代のデータ更新の標準のやり方です。

  • APIルート不要 : route.ts を書く必要がない。
  • 型安全 : 引数や戻り値に型が付くので開発しやすい。
  • 直感的 : 関数を呼ぶ感覚でサーバーと通信できる。

データの取得(Fetch)だけでなく、データの更新(Action)も習得すれば、本格的なWebアプリが作れるようになります。