React 19 has many new form-related features:
- Server actions – Call async functions that run on the server in a client component
- useActionState – Update state based on a form action
- useFormStatus – Get a form’s status
- useOptimistic – Optimistically update the UI before an async call completes
I’ve been experimenting with these.
Benefits
- Encourages web standards like <form> tags with an action, hidden inputs, and submit buttons. No more event.preventDefault!
- Graceful degradation. With React Server Components and useActionState, the form is interactive before client JS has executed. (But see concerns below).
- Nice DX for simple scenarios. Can easily declare initial form state, call a server action, and read the action’s response via state.
- useFormStatus provides the pending state of any parent component. So, I can create a reusable submit button that can “see” whether its parent form is pending. No custom state or props required!
- When I can’t use a <form> and useActionState (for reasons I outline below), I call useTransition (already in React 18). useTransition helps me update the state without blocking the UI, keeps my app responsive on slow devices, and gives me control over loading indicators via the isPending flag that it returns.
- Less custom form code.