06 May 2024
by
Hector Sosa
Simplify Form Handling in React 19: Introducing `useActionState` Hook
typescript
react
Do you need a reliable partner in tech for your next project?
React 19's new
useActionState
hook simplifies handling asynchronous operations in React, especially when dealing with forms. Let's delve into a practical example to see it in action.Here we have a simple read-only form ready for submission:
1"use client";
2
3export const FormAction = () => {
4 return (
5 <div>
6 <form>
7 <input type="text" name="name" value="Hello from actions" readOnly />
8 <button type="submit">Submit</button>
9 </form>
10 <footer>
11 <p>Awaiting action 🚀</p>
12 </footer>
13 </div>
14 );
15};
The
useActionState
hook takes a minimum of two arguments: (1) an asynchronous action, that in turn takes its own arguments of previousState
and a generic payload, and (2) an initial state. This hook returns (a) the awaited state, (b) a dispatcher and (c) an isPending
boolean.1// canary.d.ts
2export function useActionState<State, Payload>(
3 action: (state: Awaited<State>, payload: Payload) => State | Promise<State>,
4 initialState: Awaited<State>
5): [
6 state: Awaited<State>,
7 dispatch: (payload: Payload) => void,
8 isPending: boolean
9];
So let's define our state's type definition along with our initial state value to begin shaping our component.
1"use client";
2
3import { useActionState } from "react";
4
5type State = { data: string; status: "SUCCESS" } | { status: "ERROR" | "INIT" };
6const initState: State = { status: "INIT" };
7
8export const FormAction = () => {
9 const [action, submitAction, isPending] = useActionState(
10 async (prevState: State, formData: FormData) =>
11 runAction(prevState, String(formData.get("name"))),
12 initState
13 );
14
15 return (
16 <div>
17 <form action={submitAction}>
18 <input type="text" name="name" value="Hello from actions" readOnly />
19 <button type="submit" disabled={isPending}>
20 Submit
21 </button>
22 </form>
23 <footer>
24 {action.status === "INIT" && <p>Awaiting action 🚀</p>}
25 {action.status === "SUCCESS" && <p>Success, all good ✅</p>}
26 {action.status === "ERROR" && <p>Error, please resubmit action ❌</p>}
27 <code>{JSON.stringify({ isPending })}</code>
28 <code>{JSON.stringify(action)}</code>
29 </footer>
30 </div>
31 );
32};
- Notice how
submitAction
, a function generated byuseActionState
, is used directly in the form'saction
attribute. This moves away from the form pattern of using callbacksonSubmit
. - The submission button is disabled based on
isPending
which allows us to manage state effectively. - As for the form's feedback mechanism, it responds dynamically to changes in action's
state
.
The
runAction
function here is a mock, simulating an API call which randomly succeds or fails returning a new state, updating the form's status to either SUCCESS
or ERROR
. This could or could not be a Server Action.1async function runAction(_prevState: State, data: string) {
2 return new Promise<State>((r) => {
3 setTimeout(
4 () =>
5 Math.random() < 0.5
6 ? r({ data, status: "SUCCESS" })
7 : r({ status: "ERROR" }),
8 1500
9 );
10 });
11}
Gotcha: while this pattern allows you to keep your UI responsive, you need to design how to handle errors. This hook doesn't return an error member, so regardless if you are using a Server Action (where you can't throw errors) or not, you might have to follow the pattern showcased here integrating errors in the action's state.
Why not leverage
useActionState
in your next React project? What do you think? Does it make it easier or not to to manage state, side effects and boilerplate in form operations?Here are some resources that we'd recommend you explore:
Check out the code snippets and demo in webscopeio/examples/tree/main/use-action-state
Let’s stay connected
Do you want the latest and greatest from our blog straight to your inbox? Chuck us your email address and get informed.
You can unsubscribe any time. For more details, review our privacy policy
Related posts
08 April 2024
Using React's Server Actions and Resend for Emails
react
typescript
resend
24 July 2023
Unraveling the Magic of .env Files: Your Friendly Guide to Custom Variables in Next.js
custom variables
next.js
react