CodeForge

React 19 de Cero a Experto / React 19 moderno

useOptimistic: UI que responde al instante

Teoría22 min20 XP

Cuando envías un mensaje de WhatsApp, aparece al instante con un relojito, aunque el servidor aún no lo confirmó. Si algo falla, se marca en rojo. Eso es la UI OPTIMISTA: asumir que la acción va a tener éxito y mostrarlo YA, corrigiendo solo si falla. Hace que la app se sienta instantánea. React 19 trae un hook dedicado, useOptimistic, que maneja ese estado temporal por ti. Hoy entiendes el patrón y cómo React lo automatiza.

El mesero que anota tu pedido de una

El patrón manual (el que ya podrías hacer)

Antes de useOptimistic, harías la ilusión a mano: agregas el item con una marca de "pendiente", y al confirmar lo reemplazas por el real (o lo quitas si falló). Corre en vivo:

Agrega un gasto: aparece al instante con opacidad y un relojito (), y ~1.2s después se confirma () o desaparece si el servidor "falló" (1 de cada 4). Funciona, pero mezclas el estado optimista con el real en el mismo array y manejas a mano la reversión. React 19 separa esas dos capas.

El "después": useOptimistic

useOptimistic toma tu estado REAL (confirmado) y te da una versión con los cambios optimistas aplicados encima. Cuando la acción termina, React descarta la capa optimista y vuelve al estado real —que para entonces ya incluye el dato confirmado (o no, si falló)—:

con-useoptimistic.tsx
import { useOptimistic, useState } from "react";

function Lista({ gastos, agregarReal }: Props) {
// estado optimista: parte del real y aplica cambios provisionales
const [optimistas, agregarOptimista] = useOptimistic(
  gastos,
  (estado: Gasto[], nuevoNombre: string) => [
    ...estado,
    { id: Date.now(), nombre: nuevoNombre, pendiente: true }, // se ve YA
  ]
);

async function accion(formData: FormData) {
  const nombre = String(formData.get("nombre"));
  agregarOptimista(nombre);   // 1. muestra el item provisional al instante
  await agregarReal(nombre);  // 2. envía al servidor de verdad
  // 3. React descarta la capa optimista sola; queda el estado real actualizado
}

return (
  <form action={accion}>
    <input name="nombre" />
    <ul>
      {optimistas.map((g) => (
        <li key={g.id} style={{ opacity: g.pendiente ? 0.5 : 1 }}>
          {g.nombre} {g.pendiente ? "⏳" : "✓"}
        </li>
      ))}
    </ul>
  </form>
);
}

useOptimistic(estadoReal, fnActualizadora) devuelve [valorOptimista, aplicarOptimista]. Llamas aplicarOptimista(dato) y la UI muestra el cambio provisional al instante; mientras tanto, tu acción real corre. Cuando termina, React DESCARTA automáticamente la capa optimista y vuelve al estado real —que ya tiene el dato confirmado, o no lo tiene si el envío falló—. No manejas la reversión a mano: si la acción no actualizó el estado real, el item optimista simplemente desaparece al descartarse la capa.

¿Qué hace useOptimistic y por qué no tienes que revertir manualmente si la acción falla?

Mini-reto

En tu proyecto React 19 (o razonando el flujo en papel): 1) parte de una lista de mensajes en useState; 2) con useOptimistic, crea [mensajesOptimistas, agregarOptimista] cuya función actualizadora añada el mensaje nuevo con enviando: true; 3) en la acción del form, llama primero agregarOptimista(texto) (se ve YA) y luego await enviar(texto) que actualiza el estado real. Piensa: ¿qué pasa en la UI si enviar lanza un error y NO actualizas el estado real?

Qué sigue

Ya haces UIs instantáneas. La siguiente novedad de React 19 es un hook con un nombre engañosamente simple: use(). Rompe reglas que creías inquebrantables —puede leer una promesa directamente, y puede llamarse dentro de un if—. La próxima lección explica qué hace y por qué es distinto a todos los demás hooks.