TOOLS BOX/ガイド/useActionState
API / Option

useActionState

Server Action の戻り値をフォームの状態として管理する React Hook。バリデーションエラーや処理結果をクライアントで受け取れる。React 18 の useFormState を React 19 で改名したもの。

reacthookformserver-actionsuseActionStateuseFormStatevalidation
所属:react

代表的な値 / 使い方

  • const [state, action, isPending] = useActionState(serverAction, null)
  • const [state, action] = useActionState<State, FormData>(serverAction, initialState)

注意点 / Pitfalls

  • ·React 18 では useFormState(react-dom)/ React 19 では useActionState(react)。インポート元が異なる
  • ·isPending は useActionState の第 3 戻り値として得られる(useFormStatus の pending とは別)
  • ·state の初期値は第 2 引数に渡す。null や {} を渡すのが一般的
  • ·Server Action の戻り値が void / undefined の場合は state が更新されない。エラー時は必ずオブジェクトを返す

一緒に使う項目

補足

Server Action と組み合わせて使う Hook。Server Action が返した値(バリデーションエラーなど)を state として受け取り、フォームの UI に反映する。isPending でローディング状態も管理できる。

何をする Hook か

Server Action の戻り値をフォームの状態として管理します。バリデーションエラーや処理結果をクライアントで受け取り、UI に反映できます。

const [state, action, isPending] = useActionState(serverAction, initialState);
戻り値内容
stateServer Action の最新の戻り値(初回は initialState
actionフォームの action に渡す関数
isPendingServer Action 実行中は true

React バージョンとインポート元

バージョンHook 名インポート元
React 18useFormStatereact-dom
React 19 以降useActionStatereact

Next.js 15 は React 19 を使うため useActionStatereact からインポートします。

基本的な使い方

// app/actions.ts
"use server";

type State = { error?: string } | null;

export async function createPostAction(
  _prevState: State,
  formData: FormData
): Promise<State> {
  const title = formData.get("title") as string;

  if (!title) {
    return { error: "タイトルを入力してください" }; // state に入る
  }

  await db.post.create({ data: { title } });
  redirect("/posts"); // 成功時はリダイレクト
}
// components/CreatePostForm.tsx
"use client";
import { useActionState } from "react";
import { createPostAction } from "./actions";

export function CreatePostForm() {
  const [state, action, isPending] = useActionState(createPostAction, null);

  return (
    <form action={action}>
      {state?.error && (
        <p className="text-sm text-red-500">{state.error}</p>
      )}
      <input name="title" required className="border px-3 py-2" />
      <button type="submit" disabled={isPending}>
        {isPending ? "作成中…" : "作成"}
      </button>
    </form>
  );
}

Server Action の型シグネチャ

useActionState に渡す Server Action は第 1 引数に prevState を受け取る形にします。

// ✅ prevState を第 1 引数に追加する
export async function myAction(
  prevState: State,   // useActionState が前の state を渡す
  formData: FormData  // フォームデータ
): Promise<State> {
  // ...
}

useFormStatus の pending との違い

useActionStateisPendinguseFormStatuspending
取得方法戻り値の第 3 要素Hook の戻り値
使える場所useActionState を呼ぶコンポーネント<form> の子コンポーネント
向いている場面フォーム全体が Client Componentボタンだけを Client Component に切り出す場合

送信ボタンの状態を子コンポーネントで参照するには → useFormStatus

Server Actions の使い方 → Server Actions

関連ドキュメント

関連サンプル

同じテーマや技術スタックを使った実装例