Form Actions and useActionState in React 19
Before React 19, a form needed state for values, errors, loading and the response. useActionState folds most of that into one hook.
The signature
const [state, formAction, isPending] = useActionState(actionFn, initialState);
// actionFn(previousState, formData) => newState
A signup form with validation
import { useActionState } from 'react';
async function signup(prevState, formData) {
const email = formData.get('email');
const password = formData.get('password');
if (!email.includes('@')) return { error: 'Enter a valid email.' };
if (password.length < 8) return { error: 'Password must be at least 8 characters.', email };
const res = await fetch('/api/signup', { method: 'POST', body: formData });
if (!res.ok) return { error: 'That email is already registered.', email };
return { success: true };
}
export default function SignupForm() {
const [state, formAction, isPending] = useActionState(signup, {});
if (state.success) return <p>Check your inbox to confirm your account.</p>;
return (
<form action={formAction}>
<input name="email" type="email" defaultValue={state.email} />
<input name="password" type="password" />
{state.error && <p role="alert">{state.error}</p>}
<button disabled={isPending}>{isPending ? 'Creating account...' : 'Sign up'}</button>
</form>
);
}
Pending state in a child: useFormStatus
import { useFormStatus } from 'react-dom';
function SubmitButton({ children }) {
const { pending } = useFormStatus(); // reads the closest parent <form>
return <button disabled={pending}>{pending ? 'Saving...' : children}</button>;
}
Things to know
- Uncontrolled inputs (
defaultValue) are the norm with actions; you read values fromFormData. - After a successful action, React resets the form's uncontrolled fields.
- In frameworks with Server Functions (such as Next.js), the action can run on the server, and the form works even before JavaScript loads.
- Always validate on the server too; client checks are only for user experience.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.