Hook useRef
Mantén un valor mutable que persiste a través de renderizados sin provocar re-renderizados.
Busca en todas las páginas de la documentación
Mantén un valor mutable que persiste a través de renderizados sin provocar re-renderizados.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Tarjeta de referencia rápida - lista para copiar y pegar.
// Variable de instancia mutable
const renderCount = useRef(0);
renderCount.current += 1;
// Referencia a elemento del DOM
const inputRef = useRef<HTMLInputElement>(null);
inputRef.current?.focus();
// Almacena el valor anterior
const prevValue = useRef(value);
useEffect(() => { prevValue.current = value; });Cuándo usarlo: Necesitas acceder a un elemento del DOM directamente, almacenar un valor mutable que no debe provocar re-renderizados, o hacer seguimiento de un valor anterior.
"use client";
import { useEffect, useRef, useState } from "react";
export function Stopwatch() {
const [elapsed, setElapsed] = useState(0);
const [running, setRunning] = useState(false);
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
useEffect(() => {
if (running) {
intervalRef.current = setInterval(() => {
setElapsed((prev) => prev + 10);
}, 10);
}
return () => {
if (intervalRef.current) clearInterval(intervalRef.current);
};
}, [running]);
const reset = () => {
setRunning(false);
setElapsed(0);
};
const minutes = Math.floor(elapsed / 60000);
const seconds = Math.floor((elapsed % 60000) / 1000);
const ms = Math.floor((elapsed % 1000) / 10);
return (
<div className="space-y-3">
<p className="text-3xl font-mono tabular-nums">
{String(minutes).padStart(2, "0")}:{String(seconds).padStart(2, "0")}.
{String(ms).padStart(2, "0")}
</p>
<div className="flex gap-2">
<button
onClick={() => setRunning((r) => !r)}
className="px-3 py-1 border rounded"
>
{running ? "Detener" : "Iniciar"}
</button>
<button onClick={reset} className="px-3 py-1 border rounded">
Reiniciar
</button>
</div>
</div>
);
}Lo que esto demuestra:
useRef para almacenar el ID del intervalo de manera que pueda ser cancelado más tardeReturnType<typeof setInterval> proporciona el tipo correcto para el ID del temporizadoruseRef devuelve un objeto mutable con una única propiedad .current.current no provoca un re-renderizadouseState, no hay una función setter - mutarás .current directamente| Parámetro | Tipo | Descripción |
|---|---|---|
initialValue | T | Valor inicial asignado a .current |
| Retorno | Tipo | Descripción |
|---|---|---|
ref | { current: T } | Objeto ref mutable |
Enfoca una entrada al montar:
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
inputRef.current?.focus();
}, []);
return <input ref={inputRef} />;Hace seguimiento del valor anterior:
function usePrevious<T>(value: T): T | undefined {
const ref = useRef<T | undefined>(undefined);
useEffect(() => {
ref.current = value;
});
return ref.current;
}Almacena el callback más reciente (evita cierres obsoletos):
const callbackRef = useRef(callback);
useEffect(() => {
callbackRef.current = callback;
});
// Usa callbackRef.current en manejadores de eventos o temporizadoresMide un elemento del DOM:
const divRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (divRef.current) {
const { width, height } = divRef.current.getBoundingClientRect();
setSize({ width, height });
}
}, []);// Ref de DOM - usa `null` como valor inicial con tipo de elemento
const divRef = useRef<HTMLDivElement>(null);
// divRef.current es HTMLDivElement | null
// Ref mutable - pasa el tipo como genérico
const countRef = useRef<number>(0);
// countRef.current es number
// Distinción: useRef<T>(null) crea RefObject<T> (readonly .current)
// useRef<T | null>(null) crea MutableRefObject<T | null>
// Para refs de DOM, usa el primer patrón; para valores mutables, usa el segundoLeyendo refs durante el renderizado - Acceder a ref.current durante el renderizado (fuera de useEffect o manejadores de eventos) puede dar resultados inconsistentes. Solución: Lee refs solo en efectos o manejadores de eventos.
Esperando re-renderizados en mutación - Actualizar ref.current no re-renderiza el componente. Solución: Si la UI debe actualizarse, usa useState en su lugar.
Ref nula en el primer renderizado - Una ref de DOM es null hasta que React la adjunta después del primer renderizado. Solución: Accede a refs de DOM dentro de useEffect o después de una verificación nula.
Confusión entre ref y state - Almacenar datos visibles en la UI en una ref significa que la pantalla nunca se actualiza. Solución: Usa refs solo para valores que no necesitan ser mostrados o que impulsen efectos secundarios.
Refs de callback vs refs de objeto - Las refs de objeto no pueden notificarte cuando el elemento cambia (por ejemplo, renderizado condicional). Solución: Usa una ref de callback ref={(node) => { ... }} cuando necesites reaccionar al adjunto/desprendimiento.
| Alternativa | Úsalo cuando | No lo uses cuando |
|---|---|---|
useState | El valor debe provocar un re-renderizado cuando cambia | Necesitas un contenedor mutable silencioso |
| Ref de callback | Necesitas ejecutar código cuando una ref se adjunta o se desprende | Solo necesitas una referencia estable a un elemento |
document.getElementById | Fuera de React (raro) | Dentro de componentes React - usa refs en su lugar |
| Variable de nivel de módulo | El valor se comparte entre todas las instancias de un componente | El valor debe ser por instancia del componente |
¿Por qué refs en lugar de variables de módulo? Las variables de nivel de módulo se comparten entre todas las instancias de un componente. Las refs son por instancia - cada componente montado obtiene su propio .current.
useRef almacena un valor mutable que persiste a través de renderizados pero no provoca re-renderizados cuando se actualiza.useState almacena un valor que provoca un re-renderizado cuando se actualiza a través de su setter.useRef para valores que la UI no muestra; usa useState para valores que la UI refleja.null hasta que React la adjunta después del primer renderizado.useEffect (que se ejecuta después del montaje) o detrás de una verificación nula.// Ref de DOM: usa nula inicial, obtén RefObject<T> (readonly .current)
const inputRef = useRef<HTMLInputElement>(null);
// Ref mutable: incluye nula en la unión genérica
const countRef = useRef<number | null>(null);
// countRef.current es number | null (mutable).current muta el objeto en su lugar; React no tiene forma de detectar este cambio.ref.current = newValue.useState en su lugar.function usePrevious<T>(value: T): T | undefined {
const ref = useRef<T | undefined>(undefined);
useEffect(() => {
ref.current = value;
});
return ref.current;
}useEffect se ejecuta después del renderizado.ref={(node) => { ... }} cuando necesites ejecutar código cuando un elemento se adjunta o se desprende (por ejemplo, renderizado condicional).const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
useEffect(() => {
intervalRef.current = setInterval(tick, 1000);
return () => {
if (intervalRef.current) clearInterval(intervalRef.current);
};
}, []);ref.current durante el renderizado (fuera de useEffect o manejadores de eventos) puede dar resultados inconsistentes..current.const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
inputRef.current?.focus();
}, []);
return <input ref={inputRef} />;null hasta que se monta, así que accede a ella dentro de useEffect con encadenamiento opcional.callbackRef.current en temporizadores o oyentes de eventos para siempre llamar a la versión más reciente.Revisado por Chris St. John·Última actualización: 16 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥