E se seus formulários pensassem sozinhos?
Imagina largar mão daquele malabarismo infinito com useState — sem mais hooks separados pra loading, erros ou sucesso. O useActionState do React 19 muda tudo. É nesse hook fundamental que os formulários saem de relíquias engonçadas pra máquinas elegantes e autogerenciáveis. E sim, você vai se perguntar como diabos codificou sem ele.
Não é papo furado. O React 19 trouxe o useActionState, um hook que embrulha suas ações assíncronas e devolve estado, função de dispatch e isPending — tudo num array limpinho. Pensa como um assistente pessoal pros seus forms: ele pega o formData no automático, roda sua lógica e atualiza a UI sem você mexer um dedo pra e.preventDefault() ou try/catch infernal.
Por que o useActionState Parece Telepatia pros Formulários?
Lembra do React 18? Você criava useState pra pending, erros, resultados. Uma bagunça gigante. Mas o lance é que o useActionState resume isso em:
const [state, dispatch, isPending] = useActionState(async (prevState, formData) => {
// Sua mágica assíncrona
return { success: true, message: "Done" };
}, initialState);
Sem gerenciar estado na mão. A ação recebe prevState (pra updates otimistas, quem sabe) e formData direto da API FormData do browser. Limpo. Potente.
Pega esse exemplo de formulário de contato direto da doc — é ouro:
Sem useState pra isPending, erro ou sucesso — o hook cuida de tudo. Sem e.preventDefault() — o atributo action resolve. A ação recebe formData direto via FormData API. Validação e tratamento de erro rolam dentro da função de ação.
Pá! Um form que valida email no server-side (ou simulado no client), mostra “Enviando…”, pisca sucesso ou erro. Botão se desabilita sozinho. Mensagem aparece. Feito em menos de 30 linhas.
Mas pera aí — não é só pra forms. Dispara ele de forma imperativa com startTransition pra botões. Tipo adicionar no carrinho:
function handleClick() {
startTransition(() => {
dispatch();
});
}
Seu contador de carrinho sobe suave, spinner gira (🌀), sem travar a UI. É como se forms ganhassem asas.
Como Trocar Seu Código Velho e Empoeirado de React 18?
Jeito antigo? Sopa de useState mais handlers de evento. Novo? Um hook só, prop action no form. Vamos refatorar um formulário pra salvar perfil.
Primeiro, a ação:
async function saveProfile(prevState, formData) {
await new Promise(r => setTimeout(r, 1000)); // API fake
const name = formData.get('name');
if (name.length < 2) return { error: 'Name too short' };
// Chama API real...
return { success: true };
}
Componente? Puro e simples:
function ProfileForm() {
const [state, formAction, isPending] = useActionState(saveProfile, { error: null });
return (
<form action={formAction}>
<input name="name" />
<button disabled={isPending}>{isPending ? 'Saving...' : 'Save'}</button>
{state.error && <p>{state.error}</p>}
</form>
);
}
Viu? Sem onSubmit. Sem setLoading(true). O hook manda no estado pending. Pra componentes filhos que precisam de status, joga useFormStatus() dentro — ele lê o pending do form pai como mágica.
Múltiplas ações? Empilha elas. Botões sociais pra like/seguir:
const [liked, likeAction] = useActionState(toggleLike, false);
const [following, followAction] = useActionState(toggleFollow, false);
Independentes. Sem interferência. Mais limpo que pares de useState com loaders próprios.
Só erros? Estado string simplifica:
const [error, submitAction, isPending] = useActionState(async (prev, formData) => {
const res = await fetch('/api/name', { body: JSON.stringify({name: formData.get('name')}) });
if (!res.ok) return await res.json().message;
return '';
}, "");
String vazia? Sem erro. Simplicidade pura.
E pra não-forms — carrinhos, likes, follows — dispatch imperativo. Versátil, tipo fita isolante, mas elegante.
Agora, minha opinião ousada: esse hook não é só comodidade. É um vislumbre do futuro server-first do React. Lembr