Usually, when working with a form, you’d want to:
a) Display a loader
b) Show validation errors
This often means managing a couple of state variables. But with the new useActionState hook introduced in React 19, there’s now a simpler way to handle it.
Demo
Codebase
In the following snippet, notice how useActionState is being used:
import { useActionState } from "react"; import Loader from "@/components/loader"; function Form() { const [error, submitAction, isPending] = useActionState( async (previousState, formData) => { const error = await updateName(formData.get("name")); if (error) { return error; } return ""; }, "" ); return ( <form action={submitAction}> Name: <input type="text" name="name" /> <button type="submit" disabled={isPending}> Save </button> {isPending && <Loader />} {error && <p>{error}</p>} </form> ); }
A couple of things to mention:
The first variable, error, is for errors. In this case, it’s a string, but it could really be any type.
The second variable, submitAction, is a function that triggers the form submission.
The third variable, isPending, is a boolean that indicates the pending state. It’s useful for disabling elements or showing a spinner when the form is being submitted.
The first parameter is the function that gets triggered by submitAction when the form is submitted.
The second parameter is the initial value for the error. In this case, it’s an empty string, but you could use something like "fill in all the fields" instead.
Input field in the form:
<input type="text" name="name" />
Can be read like this:
formData.get("name");
name is the name of the input field.
error will display any error from the server. If there’s none, it will be empty.
isPending is automatically updated by the hook to true when the form is submitted and set back to false once the backend response is received.
if there’s no error, useActionState also handles resetting the form.
For this demo, the updateName function is pretty basic, it just makes a POST request to the backend, passing the name. If the backend returns an error, the function returns it; otherwise, it returns an empty string, meaning there was no error from the server.
async function updateName(name) { const response = await fetch("/lambda-function", { method: "POST", body: JSON.stringify({ name }), }); if (!response.ok) { const { message } = await response.json(); return message; } return ""; }
I'm using a simple lambda function that just checks if the name is a string with at least 2 characters. There’s also a 2 second delay, just to give the UI a bit of time to show the spinner.
import { useActionState } from "react"; import Loader from "@/components/loader"; function Form() { const [error, submitAction, isPending] = useActionState( async (previousState, formData) => { const error = await updateName(formData.get("name")); if (error) { return error; } return ""; }, "" ); return ( <form action={submitAction}> Name: <input type="text" name="name" /> <button type="submit" disabled={isPending}> Save </button> {isPending && <Loader />} {error && <p>{error}</p>} </form> ); }
React 19's useActionState hook is helpful when dealing with two things you should always have in a form: a pending state and validation errors. The hook takes care of updating those "state variables" and even provides a reference to previousState if you want to compare values.
What happens after the form is submitted and no error is returned is up to the application. In most cases, this means redirecting the user to another page or showing a success message.
The above is the detailed content of React New hook useActionState. For more information, please follow other related articles on the PHP Chinese website!