Deviopath › Next.js

Form with useActionState

Medium · Server Actions

React 19's useActionState wraps an action (like a Server Action) and keeps its latest result as state:

``tsx const [state, dispatch, isPending] = useActionState(saveProfile, initialState); ``

Calling dispatch(payload) runs saveProfile(previousState, payload). Whatever the action returns becomes the new state, and isPending is true while it runs. The server can send back validation errors or a success message, and the form just renders state.

The most common way is <form action={dispatch}>: React then collects the fields into a FormData, runs the action in a transition, and resets the form afterwards. Here the inputs are **controlled** (kept in useState), so you call the action yourself. That is also what you do when the data does not come straight from a form, e.g. with a form library. In that case dispatch must be called **inside a transition**, otherwise isPending does not update:

``tsx startTransition(() => dispatch({ name, email })); ``

The fake server action saveProfile and the input state are already written. Finish ProfileForm:

- Use useActionState(saveProfile, initialState) and dispatch { name, email } from onSubmit (inside startTransition, after event.preventDefault()).

- Show each field error from state.errors in a <p className="error">.

- While pending, the submit button is disabled and reads Saving…, otherwise Save.

- Show state.message in a <p className="success"> when it is not empty.

Next: Optimistic Like Button