useActionState do React 19: Exemplos Práticos

Cansado de brigar com spinners de loading e estados de erro em todo formulário? O hook useActionState do React 19 chega como super-herói, empacotando tudo num pacote elegante.

useActionState do React 19: O Hook que Faz Formulários Virarem Diversão — theAIcatchup

Key Takeaways

  • O useActionState elimina useStates separados pra loading, erros e resultados num hook só.
  • Funciona com forms via prop action; de forma imperativa pra botões usando dispatch.
  • Combina com useFormStatus pra componentes filhos e facilita validação server-side.

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

Elena Vasquez
Written by

Senior editor and generalist covering the biggest stories with a sharp, skeptical eye.

Worth sharing?

Get the best AI stories of the week in your inbox — no noise, no spam.

Originally reported by dev.to