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 concurrentesuseTransitionyuseDeferredValuese evalúan en los cuestionarios, ya que su efecto depende del planificador asíncrono de React.