0Pricing
React Academy · Lesson

useActionState and useFormStatus

Use useActionState to track pending state and errors, and useFormStatus to disable submit buttons during flight.

useActionState and useFormStatus is a free React Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the React Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Introducing useActionState

useActionState(action, initialState) is a React 19 hook that wraps a Server Action to track its state across submissions. It takes the action function and an initial state value, and returns a tuple you can use to drive the entire form experience.

The Return Tuple

The hook returns [state, formAction, isPending]. The state holds the most recent return value of the action (starting as null or your initial value). formAction is the wrapped action to pass to the form. isPending is true while the action is executing on the server.

Tracking State Between Submissions

Each time the form is submitted, the Server Action runs and its return value becomes the new state. On the first render, state equals initialState. This makes it straightforward to show different UI depending on whether there have been previous submissions and what they returned.

Showing Inline Validation Errors

If the Server Action returns { errors: { email: 'Invalid email' } }, you can display the error inline: {state.errors?.email && <p>{state.errors.email}</p>}. Because the state persists across re-renders, the error message stays visible until the next successful submission replaces the state.

Showing Success Messages

When the action returns { success: true }, the component can render a success message: {state?.success && <p>Form submitted!</p>}. The form can be conditionally hidden or replaced by the success message based on the state value.

Introducing useFormStatus

useFormStatus() is a hook that reads the pending state of the nearest ancestor <form> element. It returns an object including { pending: boolean }. This hook must be used inside a component that is a child of the form — not in the component that renders the form itself.

Why the Location Restriction Exists

The restriction that useFormStatus must be used inside the form exists because the hook reads the form's context from the React tree above it. If called in the same component that renders the form, it would be a sibling of the form, not a descendant, and would not have access to the form's state.

Creating a Submit Button Component

The standard pattern is to extract the submit button into its own component: function SubmitButton() { const { pending } = useFormStatus(); return <button disabled={pending}>Submit</button>; }. This component is then placed inside the form, giving it access to the form's pending state.

Disabling the Submit Button

Setting disabled={pending} on the submit button prevents double submissions. When the user clicks submit and the Server Action is executing, pending is true, the button becomes disabled and unclickable. When the action completes, pending returns to false and the button re-enables.

Combining Both Hooks

The complete form UX pattern combines both hooks: useActionState in the form component tracks the action result and provides formAction, while useFormStatus inside a child SubmitButton component tracks pending state. Together they provide validated error display and a responsive submit button.

Optimistic UI with useOptimistic

For an even more responsive feel, useOptimistic pairs with useActionState. You immediately update the UI with the expected result before the server responds, then reconcile when the actual response arrives. This pattern is common in like buttons, todo lists, and other fast-feedback interactions.

useFormStatus Location

Where must useFormStatus be called for it to work correctly?

Lesson Recap

useActionState(action, initialState) returns [state, formAction, isPending] to track Server Action results. The state holds the action's return value, enabling inline error and success display. useFormStatus() provides { pending } inside child components of the form, enabling responsive submit buttons. Both hooks together create a complete, accessible form experience.

Frequently asked questions

Is the “useActionState and useFormStatus” lesson free?

Yes — the full text of “useActionState and useFormStatus” is free to read here on the web, and the React Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the React Academy course, upgrade to CoddyKit PRO.

What will I learn in “useActionState and useFormStatus”?

Use useActionState to track pending state and errors, and useFormStatus to disable submit buttons during flight. You practise React Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start React Academy?

No prior experience is required. React Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “useActionState and useFormStatus” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this React Academy lesson?

Yes. Every React Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Server Actions in React 19 and Next.js
  2. Form Actions: Replacing API Routes for Mutations
  3. useActionState and useFormStatus
  4. Progressive Enhancement with Server Actions
← Back to React Academy