TOOLS BOX/ガイド/useFormStatus
API / Option

useFormStatus

親フォームの送信状態(pending)をコンポーネントから参照する React DOM Hook。送信中のボタン無効化やローディング表示に使う。

reacthookformpendinguseFormStatusloading
所属:react-dom

代表的な値 / 使い方

  • const { pending } = useFormStatus()
  • const { pending, data, method } = useFormStatus()

注意点 / Pitfalls

  • ·useFormStatus は親の <form> の直接の子コンポーネントで使う必要がある。フォームと同じコンポーネントに書いても機能しない
  • ·react-dom からインポートする(react ではない)
  • ·pending は親フォームの送信中のみ true になる。useActionState の isPending とは別物
  • ·form が Server Component で、送信ボタンが Client Component の場合は useFormStatus が自然な選択

一緒に使う項目

補足

送信ボタンだけを Client Component として切り出し、その中で useFormStatus を使うのが典型パターン。フォーム全体を Client Component にせずに済む。

何をする Hook か

親フォームの送信状態を子コンポーネントから参照します。送信中にボタンを無効化したりローディング表示を出したりする場面で使います。

import { useFormStatus } from "react-dom";

const { pending, data, method, action } = useFormStatus();
フィールド内容
pendingフォーム送信中は true
data送信中の FormData(送信完了後は null
methodフォームの HTTP メソッド
actionフォームの action 属性の値

典型パターン:ボタンを Client Component に切り出す

フォーム全体を "use client" にせず、送信ボタンだけを Client Component に切り出すパターンが最もよく使われます。

// components/SubmitButton.tsx
"use client";
import { useFormStatus } from "react-dom";

export function SubmitButton({ label }: { label: string }) {
  const { pending } = useFormStatus();
  return (
    <button
      type="submit"
      disabled={pending}
      className="rounded bg-blue-600 px-4 py-2 text-white disabled:opacity-50"
    >
      {pending ? "送信中…" : label}
    </button>
  );
}
// app/posts/new/page.tsx(Server Component のままでよい)
import { createPostAction } from "./actions";
import { SubmitButton } from "@/components/SubmitButton";

export default function NewPostPage() {
  return (
    <form action={createPostAction}>
      <input name="title" required />
      <SubmitButton label="作成" />
    </form>
  );
}

注意:親フォームの直接の子でないと機能しない

useFormStatus呼ばれているコンポーネントの外側にある <form> の状態を参照します。フォームと同じコンポーネント内に書いても機能しません。

// ❌ フォームと同じコンポーネントで useFormStatus を使っても pending にならない
"use client";
export function MyForm() {
  const { pending } = useFormStatus(); // ← この form の pending は取れない
  return (
    <form action={myAction}>
      <button disabled={pending}>送信</button>
    </form>
  );
}

// ✅ 子コンポーネントに切り出す
"use client";
function SubmitButton() {
  const { pending } = useFormStatus(); // ← 親の form の pending が取れる
  return <button disabled={pending}>送信</button>;
}

useActionState の isPending との使い分け

フォーム全体がすでに "use client" になっている場合は、useActionStateisPending を使う方がシンプルです。

// フォーム全体が Client Component なら useActionState の isPending で十分
const [state, action, isPending] = useActionState(myAction, null);
return (
  <form action={action}>
    <button disabled={isPending}>送信</button>
  </form>
);

フォームの状態・エラーを受け取るには → useActionState

Server Actions の使い方 → Server Actions

関連ドキュメント

関連サンプル

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