A better way to display the loading state in Nextjs forms with useFormStatus

In this tutorial, we will learn about the basics of useFormStatus. We will cover everything you need to know about useFormStatus. Let’s get started.

Video tutorial

Check the video for better understanding.

Why do we need useFormStatus?

When user submits a form and the form is being processed, it is a good practice to show a loading indicator to the user and disable the submit button. Previously you would create a separate state and manipulate the state inside submit handler. Similar to this:

const Form = () => {
const [loading, setLoading] = useState(false)

const handleSubmit = async e => {
e.preventDefault()
setLoading(true)
// … your form submission logic
setLoading(false)
}

return (
<form onSubmit={handleSubmit}>
<input type=text name=name />
<button type=submit disabled={loading}>
Submit
</button>
</form>
)
}

This is fine but it would have been nice if react could handle this logic for us.
And this is where useFormStatus comes in. It is specially useful when you use server action in nextjs

How to use useFormStatus?

// Form.jsx

const Form = () => {
const handleSubmit = async data => {
console.log(data.get(name)) // Prints the input value
// … your form submission logic
}

return (
<form action={handleSubmit}>
<input type=text name=name />
<SubmitButton />
</form>
)
}

// SubmitButton.jsx
use client
import { useFormStatus } from react-dom

const SubmitButton = () => {
const { pending } = useFormStatus()

return (
<button type=submit disabled={pending}>
Submit
</button>
)
}

Explanation:

Like before we have a handleSubmit function but this time we passed in action prop.

handleSubmit takes a argument which is the FormData. You can get the input value using the get method.
We have a separate submit button component. And we use the useFormStatus hook.

useFormStatus returns an object with a pending property. pending is true when the form is being submitted and false when the form submission is complete.
Btw, with use client we are making the button component a client component since all components are server component by default in Nextjs.

useFormStatus actually returns four things:

pending: true when the form is being submitted and false when the form submission is complete.

action: The action function passed to the form.

data: The FormData object.

method: The submit method. GET or POST etc.

action, data and method are null when the form is not being submitted.

So, this is how you can use useFormStatus to handle form submission status.

Things to keep in mind

Form submission function should be passed to the form using the action prop.
The handler function has to be async or return a promise.

useFormStatus should be used inside a component that is a child of the form.

// This will not work
const Form = () => {
const { pending } = useFormStatus()
return (
<form>
<input type=text name=name />
<button type=submit disabled={pending}>
Submit
</button>
</form>
)
}

// This will work
const Form = () => {
return (
<form>
<input type=text name=name />
<SubmitButton />
</form>
)
}

const SubmitButton = () => {
const { pending } = useFormStatus()
return (
<button type=submit disabled={pending}>
Submit
</button>
)
}

That’s it for this tutorial. I hope you find this tutorial helpful. If yes, please subscribe to my channel for more tutorials like this.
If you have any questions, feel free to ask in the comments below.

Leave a Reply

Your email address will not be published. Required fields are marked *