Question presented to candidate:
"What does useActionState give you that a useState plus a loading flag does not?"
What a strong answer should cover:
- It returns a three-element tuple:
[state, formAction, isPending]. - It is shaped like a reducer whose action function may be async: it receives the previous state and the FormData, and whatever it returns becomes the new state.
- That previous-state argument is the real difference from
useState— retry counts, accumulated errors, and "last submitted values" come for free. isPendingis React's, not yours, because the call runs inside a transition. NosetSubmitting(true)/finallypair.- The idiomatic error strategy is to catch inside the action and return the error as state, rather than throwing to an error boundary — a bad email should not blank the page.
- The
formActionit returns is passed to<form action={...}>, or to a button'sformAction. - With a framework it supports progressive enhancement: the form posts before hydration, and the returned state is available afterwards.
- It replaces the React 18 canary name
useFormState, and lives inreact, notreact-dom.
Clarifying questions expected:
- "Does the result need to survive between submissions?" — that is what the state argument is for.
- "Is this validation, which should be state, or a genuine crash, which should throw?"
Code / implementation expected: Optional. Showing the (prevState, formData) => newState signature is the substance.