DevPath · Aprende a programar ESPTEN

React moderno: Suspense, lazy, Portals y concurrencia

Refs avanzadas y concurrencia

forwardRef: exponer una ref a través de un componente

Las ref no se pasan como una prop normal. Si quieres que un componente padre obtenga una referencia a un nodo dentro de un componente hijo, ese hijo debe reenviar la ref con React.forwardRef:

const Input = React.forwardRef(function Input(props, ref) {
  return <input ref={ref} {...props} />;
});

function Formulario() {
  const inputRef = React.useRef(null);
  // inputRef.current apuntará al <input> real del hijo
  return <Input ref={inputRef} />;
}

useImperativeHandle: personalizar lo que expone la ref

A veces no quieres dar acceso al nodo DOM entero, sino solo a unas acciones concretas (un mini-API imperativa). useImperativeHandle define exactamente qué verá el padre a través de la ref:

const Campo = React.forwardRef(function Campo(props, ref) {
  const inputRef = React.useRef(null);
  React.useImperativeHandle(ref, () => ({
    enfocar: () => inputRef.current.focus(),
    limpiar: () => { inputRef.current.value = ""; },
  }));
  return <input ref={inputRef} />;
});

// El padre puede llamar a campoRef.current.enfocar() — y nada más.

Es un patrón excepcional: úsalo solo para acciones imperativas reales (foco, scroll, reproducir/pausar). Para datos, sigue prefiriendo props y estado.

Hooks concurrentes: mantener la UI responsiva

React moderno puede interrumpir y priorizar renderizados. Dos hooks aprovechan esto para que el trabajo costoso no congele la interfaz:

useTransition

Marca una actualización de estado como no urgente (una transición). React la procesa con baja prioridad, dejando que las interacciones urgentes (escribir en un input) respondan al instante. Además da un isPending para mostrar un indicador de carga:

const [isPending, startTransition] = useTransition();

function buscar(texto) {
  setTexto(texto);                 // urgente: el input se actualiza ya
  startTransition(() => {
    setResultados(filtrar(texto)); // no urgente: puede esperar/interrumpirse
  });
}

useDeferredValue

Recibe un valor y devuelve una versión "retrasada" de él. Mientras llega un valor nuevo, React puede seguir mostrando el anterior, evitando recalcular una lista pesada en cada pulsación:

const consultaDiferida = useDeferredValue(consulta);
// La lista cara se filtra con consultaDiferida, no con consulta.

Ambos persiguen lo mismo: que escribir o hacer clic se sienta fluido aunque haya un render caro en segundo plano.

useId: identificadores únicos y estables

React.useId genera un id único y estable para el componente, idéntico en el servidor y en el cliente (clave para evitar errores de hidratación). Su uso estrella es la accesibilidad: vincular un <label> con su <input>.

function Campo() {
  const id = React.useId();
  return (
    <div>
      <label htmlFor={id}>Nombre</label>
      <input id={id} />
    </div>
  );
}

Así no necesitas inventar ids a mano (que chocarían si el componente se usa varias veces en la página). Nunca uses useId para generar keys de listas: es para ids de elementos del DOM.

En el ejercicio de código practicarás React.useId (síncrono y validable). Los hooks concurrentes useTransition y useDeferredValue se evalúan en los cuestionarios, ya que su efecto depende del planificador asíncrono de React.

Pon esto en práctica

DevPath es un curso práctico: aquí lees la teoría; en la app la pones en práctica con ejercicios que se ejecutan de verdad, sin conexión.

Empezar gratis en la app →
← Portals: renderizar fuera del árbol del DOMVer el módulo →