Skip to content
Daily Dev Tip

This tip lives in your new tab — for free.

Install for Chrome →
REACT

Handle form mutations with built-in pending and error state via useActionState

app/components/ContactForm.tsx
tsx
'use client'
import { useActionState } from 'react'

const [state, submitAction, pending] = useActionState(
  async (_prev: State, formData: FormData) => {
    const res = await sendMessage(formData)
    return res.ok ? { ok: true } : { error: 'Failed' }
  },
  { ok: false },
)

<form action={submitAction}>
  <button disabled={pending}>Send</button>
  {state.error && <p>{state.error}</p>}
</form>

`useActionState` wraps an async action and returns the last result, the action to bind to a `<form action>`, and a `pending` flag — no manual `isSubmitting` state or try/catch bookkeeping. The reducer-style signature `(prevState, formData) => newState` keeps error and success handling in one place, and pending is managed by React across the transition. It's the React 19 replacement for the ad-hoc loading/error `useState` trio around form submits.

react19formsactionsstate