useOptimistic: Atualizações Otimistas no React 19

Como o hook useOptimistic do React 19 mostra o resultado esperado de uma Action antes da confirmação do servidor, revertendo automaticamente para o estado real em caso de erro.

Quando o usuário curte um post ou envia uma mensagem, esperar a resposta do servidor para só então atualizar a tela deixa a interface com uma sensação de atraso. O hook useOptimistic, estabilizado no React 19, resolve exatamente isso: ele mostra um estado "otimista" — o resultado que você espera que a Action produza — enquanto a operação assíncrona ainda está em andamento, e volta automaticamente para o estado real quando ela termina.

O problema sem useOptimistic

Sem o hook, atualizar a UI antes da resposta do servidor exige controlar manualmente um estado "visual" separado do estado real, revertendo-o à mão em caso de erro:

function BotaoCurtir({ post }) {
    const [curtidasExibidas, setCurtidasExibidas] = useState(post.curtidas);

    async function curtir() {
        setCurtidasExibidas(c => c + 1);
        try {
            await enviarCurtida(post.id);
        } catch (e) {
            setCurtidasExibidas(c => c - 1); // reverte manualmente
        }
    }

    return <button onClick={curtir}>♥ {curtidasExibidas}</button>;
}

Como funciona o useOptimistic

O hook recebe o estado real atual e uma função de atualização, e devolve o estado otimista mais uma função addOptimistic para disparar uma atualização temporária. Enquanto nenhuma Action estiver pendente, o estado otimista é idêntico ao estado real; durante uma Action pendente, ele reflete o valor otimista até o estado real ser atualizado:

const [curtidasOtimistas, adicionarCurtidaOtimista] = useOptimistic(
    post.curtidas,
    (curtidasAtuais, incremento) => curtidasAtuais + incremento
);

Aplicando isso ao botão de curtir, a atualização visual acontece no mesmo instante do clique, dentro de uma Action — e se a chamada ao servidor falhar, o React descarta o valor otimista e volta para post.curtidas sozinho, sem precisar de um reverso manual:

function BotaoCurtir({ post }) {
    const [curtidasOtimistas, adicionarCurtidaOtimista] = useOptimistic(
        post.curtidas,
        (curtidasAtuais, incremento) => curtidasAtuais + incremento
    );

    async function curtir() {
        adicionarCurtidaOtimista(1);
        await enviarCurtida(post.id); // atualiza post.curtidas no servidor
    }

    return (
        <form action={curtir}>
            <button>♥ {curtidasOtimistas}</button>
        </form>
    );
}

Exemplo prático: chat com envio otimista

Combinado com useActionState, é possível exibir a mensagem na lista antes mesmo do servidor confirmar o envio, marcando-a como pendente enquanto a Action não termina:

function Chat({ mensagens, enviarMensagem }) {
    const [mensagensOtimistas, adicionarMensagemOtimista] = useOptimistic(
        mensagens,
        (atuais, novaMensagem) => [...atuais, { ...novaMensagem, pendente: true }]
    );

    async function handleSubmit(formData) {
        const texto = formData.get('texto');
        adicionarMensagemOtimista({ id: Date.now(), texto });
        await enviarMensagem(texto);
    }

    return (
        <>
            <ul>
                {mensagensOtimistas.map(m => (
                    <li key={m.id} style={{ opacity: m.pendente ? 0.5 : 1 }}>
                        {m.texto}
                    </li>
                ))}
            </ul>
            <form action={handleSubmit}>
                <input name="texto" />
                <button>Enviar</button>
            </form>
        </>
    );
}

Quando a lista real mensagens chegar atualizada do servidor (via revalidação ou nova prop), o React substitui a versão otimista pela real automaticamente, removendo a marca de pendente.

Quando usar

Cuidados

useOptimistic não substitui o tratamento de erro: se a Action falhar, o estado otimista desaparece, mas cabe ao código da Action decidir se mostra uma mensagem de erro ou tenta de novo. O estado otimista também só existe enquanto a atualização do estado real correspondente não chega — chamar addOptimistic fora de uma Action (por exemplo, em um useEffect qualquer) funciona, mas perde o sentido do hook, que foi desenhado para o ciclo de vida de Actions.

Compatibilidade

useOptimistic foi introduzido e estabilizado no React 19 (dezembro de 2024), exportado diretamente do pacote react. Funciona em React DOM com Actions de formulário ou disparadas manualmente, sem flag ou configuração extra a partir dessa versão.

documentação oficial

Conclusão

useOptimistic cobre um padrão de UI comum — mostrar o resultado esperado antes da confirmação do servidor — sem exigir um segundo estado controlado manualmente. O resultado é uma interface que responde no instante da interação e volta ao estado real sozinha, inclusive em caso de erro.

Tecnologia:
react

Deixe seu Comentário!

Dúvida, sugestão ou só um "valeu!" — tudo é bem-vindo por aqui.

Comentário
Nome
Email
lock Seu e-mail não será publicado.