useRef, useMemo y useCallback
useRef es como una caja con tapa: guarda un valor en .current que puedes modificar sin que React se entere ni re-renderice.
Es perfecta para acceder al DOM directamente (enfocar un input, medir su tamaño) o para guardar valores que el componente necesita internamente pero que no deben aparecer en pantalla, como el ID de un intervalo o la cantidad de renders. Cambiar .current no dispara un nuevo render, a diferencia de setState.
useMemo y useCallback son hermanos que guardan resultados en caché. useMemo guarda el resultado de un cálculo costoso: "si los datos no cambiaron, devuelve el número guardado sin recalcular". useCallback guarda la referencia de una función: sin él, cada render crea una nueva función con diferente dirección de memoria, lo que hace que React.memo no pueda detectar que "es la misma función" y re-renderice igual. Úsalos solo cuando mides un problema real de rendimiento con React DevTools Profiler.
import { useRef, useMemo, useCallback, useState } from "react";
function EjemplosHooks() {
const [lista, setLista] = useState([1,2,3,4,5,6,7,8,9,10]);
const [filtro, setFiltro] = useState(0);
// useRef - referencia al DOM (no dispara re-renders)
const inputRef = useRef(null);
const enfocarInput = () => inputRef.current.focus();
// useRef para guardar valores sin re-renderizar
const contadorRenders = useRef(0);
contadorRenders.current++;
// useMemo - memoiza el resultado de cálculos
// Solo recalcula cuando cambia [lista, filtro]
const listaFiltrada = useMemo(() => {
console.log("Filtrando..."); // Solo cuando cambia
return lista.filter(n => n > filtro);
}, [lista, filtro]);
// useMemo para objetos (evitar re-renders innecesarios)
const estilos = useMemo(() => ({
color: filtro > 5 ? "red" : "green"
}), [filtro]);
// useCallback - memoiza funciones (referencia estable)
const agregar = useCallback(() => {
setLista(prev => [...prev, prev.length + 1]);
}, []); // Sin deps = misma función siempre
return (
<div>
<input ref={inputRef} placeholder="Ingresa algo" />
<button onClick={enfocarInput}>Enfocar</button>
<input
type="number"
value={filtro}
onChange={e => setFiltro(Number(e.target.value))}
/>
<p style={estilos}>Renders: {contadorRenders.current}</p>
<ul>{listaFiltrada.map(n => <li key={n}>{n}</li>)}</ul>
</div>
);
}
Practica esta lección
Resuelve los ejercicios del curso de React en la app, gratis y con corrección automática.
Empezar a practicar