Next.js (App Router): The useActionState hook

Join the AI Workshop to learn more about AI and how it can be applied to web development. Next cohort February 1st, 2026

The AI-first Web Development BOOTCAMP cohort starts February 24th, 2026. 10 weeks of intensive training and hands-on projects.


(in previous React canary versions known as useFormState)

Client components can use this new hook to “peek” into the state of a server action.

We basically pass it the server action, and an initial state object.

What we get back is the state object, the form action we attach to the form, and the pending object:

"use client"

import { useActionState } from "react"

import { myServerAction } from './actions'

const initialState = {
  message: "",
}

export const Demo = () => {
  const [state, formAction, pending] =
    useActionState(myServerAction, initialState)

  return (
    <div>
      <form action={formAction}>
        <input
          type='text'
          name='fullName'
        />
        {state?.message && <p>{state.message}</p>}
        <button
          aria-disabled={pending}
          type='submit'>
          {pending ? "Submitting..." : "Submit"}
        </button>
      </form>
    </div>
  )
}

Basically we have a very easy way of handing feedback from the server action (in this case we assume it returns an object with a message string), and we have an easy way of handling the pending state, so we can disable the button while the action is running.

Stuff we didn’t implement before, but you can see how it’s quick to implement using useActionState.

Lessons in this unit:

0: Introduction
1: Server Actions
2: Next.js, passing an id to a server action
3: The use hook
4: use() and data fetching
5: The useFormStatus Hook
6: The useOptimistic hook
7: ▶︎ The useActionState hook
8: How to get the Request headers in Next.js app router
9: How to install shadcn-ui on latest Next.js beta-RC