useActionState é um hook do React 19 que executa uma função assíncrona (uma action), guarda como estado o que ela retornar e diz se ela ainda está executando. Você o chama como const [state, formAction, isPending] = useActionState(action, initialState) e passa formAction para um <form>.
Envie primeiro o formulário vazio: a action retorna um objeto de erro e a mensagem aparece. Depois digite um endereço com @ e envie de novo. Por um segundo o botão mostra "Subscribing..." e fica desabilitado.
A sintaxe
const [state, formAction, isPending] = useActionState(action, initialState, permalink?);
actioné a função a executar. O React a chama comoaction(previousState, ...args). O que ela retornar (ou resolver, se for assíncrona) vira o novostate.initialStateé o estado antes de a action executar pela primeira vez. Use o mesmo formato que a action retorna, para que o componente também consiga lerstate.messagena primeira renderização.stateé o resultado mais recente.formActioné uma versão envolvida da sua action. Passe-a para<form action>ou<button formAction>, ou chame-a você mesmo.isPendingétruedesde o momento em que a action começa até ela terminar.permalinké opcional e só importa para Server Functions em um framework: a URL para onde o formulário deve ir se for enviado antes de o JavaScript carregar.
A action recebe o estado anterior como primeiro argumento. Esse é o erro mais comum ao migrar um formulário: escrever async function save(formData) coloca o estado antigo em formData, e formData.get lança um erro.
Lendo o formulário com FormData
Quando formAction é usada como action de um formulário, o React chama a sua action com o FormData do formulário. Todos os campos com name estão nele. Você não precisa de useState para os inputs nem de um handler de onChange, e não chama e.preventDefault(): o React cuida do evento de envio.
Desmarque Spicy e envie de novo: a chave spicy desaparece dos dados registrados, porque um checkbox desmarcado não envia nada. A action também lê previousState.count para somar um, e é por isso que o estado anterior vem primeiro.
Retornando erros de validação
A validação fica na action. Retorne os erros como parte do estado e retorne os valores que o usuário digitou para que o formulário possa colocá-los de volta. Depois que uma form action termina, o React reinicia os campos não controlados do formulário, então um campo sem defaultValue={state.values...} voltaria vazio depois de um envio com falha.
Digite um nome de uma letra e uma senha curta e envie. Os dois erros aparecem e os dois campos mantêm o que você digitou. Remova defaultValue={state.values.name} e envie de novo: o campo de nome se esvazia depois do erro.
Em um app real, mantenha o servidor como juiz final. As verificações no cliente dão retorno rápido, mas qualquer pessoa pode enviar uma requisição sem o seu formulário.
Chamando a action fora de um formulário
formAction é uma função, então um botão ou um efeito também pode chamá-la. Quando você mesmo a chama, envolva a chamada em startTransition. Um formulário faz isso por você; um onClick comum não, e sem uma transição isPending não atualiza corretamente (o React registra um erro sobre isso em desenvolvimento).
Clique em Load more algumas vezes. Cada chamada parte do estado que a anterior retornou, então as páginas são adicionadas em ordem. Se você chamar a action de novo enquanto ela ainda está executando, o React enfileira a chamada e a executa depois da atual, cada uma com o estado mais recente.
De onde veio o useActionState
Antes do lançamento do React 19, este hook estava disponível nas versões canary como useFormState, importado de react-dom. Ele foi renomeado para useActionState, movido para react e ganhou o valor isPending. Se você encontrar código antigo como este, a correção é o import e o nome:
// React canary, before 19
import { useFormState } from 'react-dom';
const [state, formAction] = useFormState(action, initialState);
// React 19
import { useActionState } from 'react';
const [state, formAction, isPending] = useActionState(action, initialState);
Para mostrar um estado pendente em um botão de envio bem aninhado, o useFormStatus de react-dom lê o status do formulário pai sem props. A visão geral do React 19 o lista junto com os outros recursos de formulário.
Erros e quando usar outra coisa
Se a action lança um erro, o React mostra o error boundary mais próximo em vez de atualizar o estado. Para erros que o usuário pode corrigir, como validação ou um nome de usuário já em uso, retorne-os como estado, como no exemplo de cadastro. Deixe as falhas de verdade lançarem erros.
O useActionState serve para o resultado de uma action. Para um valor que atualiza na hora enquanto a action executa, como uma contagem de curtidas que deve subir no clique, combine-o com o useOptimistic. Para entradas que mudam a cada tecla e são lidas durante a renderização, useState e um input controlado continuam sendo a ferramenta certa.
Erros comuns
Esquecer o parâmetro do estado anterior. async function save(formData) recebe o estado anterior em formData. A assinatura é sempre (previousState, formData) para um formulário.
Inputs sem name. O FormData só contém campos que têm um atributo name. Um campo só com id fica de fora de formData.get(...), que retorna null.
Inputs controlados em todo lugar. Você ainda pode usar value e onChange dentro de uma form action, mas não precisa. Campos não controlados com name e defaultValue combinam de forma mais simples com actions, e a reinicialização do React depois do envio só afeta campos não controlados.
Ler o estado dentro da action. O state do componente é o valor da renderização que criou o handler. Dentro da action, use previousState, que é sempre o resultado da chamada anterior, mesmo quando várias chamadas foram enfileiradas.
Lançar erros para erros esperados. Um erro lançado substitui o formulário pelo error boundary mais próximo. Uma senha errada não é um travamento; retorne-a como estado.
Perguntas frequentes
O que o useActionState retorna?
Um array de três itens: o estado atual (o último valor que a action retornou, ou o estado inicial antes de ela executar), uma nova action para passar a um formulário ou chamar você mesmo e isPending, que é true enquanto a action executa.
Quais argumentos a action recebe?
Primeiro o estado anterior, depois o que a action recebeu na chamada. Em um <form action={formAction}>, esse segundo argumento é o FormData do formulário.
Qual é a diferença entre useActionState e useFormState?
São o mesmo hook. Ele saiu nas versões canary do React como useFormState em react-dom, foi renomeado para useActionState e movido para react no React 19 e ganhou o valor isPending ao mesmo tempo.
Posso usar o useActionState sem um formulário?
Sim. Chame você mesmo a action retornada, dentro de startTransition, por exemplo a partir do onClick de um botão. Sem uma transição, isPending não atualiza corretamente e o React registra um erro em desenvolvimento.
Por que meu formulário é limpo depois do envio?
Depois que uma form action termina, o React reinicia os campos não controlados do formulário, como um navegador faz depois de um envio normal. Para manter um valor depois de um erro, retorne-o no estado e passe-o para o defaultValue do campo.