useActionState: formuláře bez zbytečného boilerplatu
Tři useState pro data, chybu a loading? React 19 to zvládne jedním hookem — a formulář funguje i před hydratací.
Klasický formulář v Reactu vypadal roky stejně: useState pro hodnoty, další pro chybu, další pro isLoading, onSubmit s preventDefault() a try/finally. React 19 přináší useActionState, který tenhle vzor zabalí do jediného hooku.
Jak to funguje
useActionState(action, initialState) vrací trojici:
state— poslední návratová hodnota akce (na začátkuinitialState),formAction— funkci, kterou předáte do<form action={…}>,isPending—true, dokud akce běží.
Akce dostane předchozí stav a FormData. Co vrátí, to se stane novým stavem.
"use client";
import { useActionState } from "react";
import { subscribe } from "./actions";
type State = { ok: boolean; message: string } | null;
export function NewsletterForm() {
const [state, formAction, isPending] = useActionState<State, FormData>(
async (_prev, formData) => {
const email = String(formData.get("email") ?? "");
if (!email.includes("@")) return { ok: false, message: "Neplatný e-mail" };
return subscribe(email);
},
null,
);
return (
<form action={formAction}>
<input name="email" type="email" required />
<button disabled={isPending}>
{isPending ? "Odesílám…" : "Odebírat"}
</button>
{state && <p role="status">{state.message}</p>}
</form>
);
}Proč je to lepší
- Žádné ručně řízené
isLoading. Pending stav drží React a nikdy se „nezasekne“ natrue, když zapomenetefinally. - Akce se řadí za sebou. Když uživatel klikne dvakrát, druhé volání dostane jako
prevvýsledek prvního. - Progressive enhancement. Pokud je akce Server Function (
"use server"), formulář se odešle i tehdy, když JavaScript ještě není načtený.
Tip na závěr
Formulář se po úspěšné akci sám resetuje (u nekontrolovaných inputů). Pokud chcete hodnoty po chybě zachovat, vraťte je ve stavu a použijte defaultValue={state?.values?.email}.