How I use useFormStatus
If you prefer to watch a code walk-through of this hook in action, please visit my React 19 useFormStatus how to
useFormStatus
makes working with complex forms, where you have multiple child forms within a parent form, much easier. Before, you would have to manage state either using context
, a state management library such as Redux
or just by storing the state in a parent and passing it down to the child components. This hook removes that added boilerplate and complexity, simply call useFormStatus
in a child of a <form>
and you can access both the pending
state and the data
of the form.
In a standard one page form, this hook isn’t too useful, however, if you have a more complicated form with multiple pages this hook saves a lot of repeated logic and state management. You may have a form where you capture “Personal Details”, “Address Details” and “Order Details” etc etc… Each of those sections can be their own page. You can use this hook to gain access to the pending
state, which will be true while the form’s action is running. This is useful for disabling buttons or displaying a loading spinner while asynchronous operations happen in your backend.
For example, even though <Submit />
is a different component to where our <form>
is defined below. We can call the useFormStatus()
hook to check if the pending
status is true:
'use client'
import { useFormStatus } from 'react-dom'
import { useActionState } from 'react'
import TextInput from '../TextInput'
function Submit() {
const status = useFormStatus()
return (
<button disabled={status.pending} type="submit">
Submit {' '}
</button>
)
}
async function submitUser(
prevState: Record<string, string>,
formData: FormData,
) {
const name = formData.get('name') as string
const email = formData.get('email') as string
console.log({ name, email })
return {
name,
email,
}
}
const initialState = {
name: '',
email: '',
}
export default function FormStatus() {
const [state, formAction, pending] = useActionState(submitUser, initialState)
return (
<form action={formAction}>
<TextInput id="name" label="Name" />
<TextInput id="email" label="Email" />
<Submit /> {' '}
</form>
)
}
useFormStatus()
gives us access to two values:
const { pending, data } = useFormStatus()
To really see this hook shine, you need to have a more complex form structure than the above, checkout my video to see how two child forms can be used within a <form>
container.