Posted by Ignacio Figueroa on Saturday, March 7, 2026
Entendiendo los Hooks más importantes de React (de verdad)
Este artículo no es una lista superficial. Vamos a desarmarlos mentalmente.
Desde la introducción de Hooks en React 16.8, la forma de escribir componentes cambió para siempre. Pero aunque muchos usamos useState y useEffect todos los días, no siempre entendemos bien qué pasa por debaj
¿Cómo funcionan realmente los Hooks?
Los Hooks funcionan gracias a una regla clave:
React asocia cada hook a un índice interno según el orden en que se ejecuta.
Por eso:
- No se pueden usar dentro de condicionales
- No se pueden usar dentro de loops
- Siempre deben llamarse en el mismo orden
React guarda internamente algo así como:
hooks = [{ state: 0 },{ effect: ... },{ state: "hola" }]
Si cambiás el orden, rompés esa asociación.
Ese detalle explica muchas “reglas raras”.
useState, Estado y renders
¿Qué hace realmente?
useState guarda un valor entre renders.
Cada vez que llamás al setter:
- React marca el componente como “dirty”
- Lo vuelve a renderizar
- Compara el nuevo Virtual DOM
- Actualiza el DOM real si es necesario
Ejemplo básico
const [count, setCount] = useState(0);
¿Por qué el setter no actualiza inmediatamente?
Porque React agrupa actualizaciones para optimizar renders (batching).
Esto falla:
setCount(count + 1);setCount(count + 1);
Porque ambas usan el mismo count.
Solución correcta:
setCount(prev => prev + 1);setCount(prev => prev + 1);
🔎 Buena práctica:
Cuando el nuevo estado depende del anterior, usá siempre la forma funcional.
useEffect, El hook más mal entendido
Este merece sección grande.
¿Qué es realmente?
useEffect permite sincronizar el componente con algo externo:
- API
- DOM
- Timers
- Suscripciones
- LocalStorage
No es para “ejecutar código después del render”.
Es para manejar efectos secundarios.
Cómo funciona internamente
Flujo simplificado:
- React renderiza el componente.
- React actualiza el DOM.
- React ejecuta los efectos.
- Si hay cleanup, lo ejecuta antes del siguiente efecto.
Los tres modos de useEffect
1️⃣ Sin dependencias
useEffect(() => {console.log("Siempre corre");});
Se ejecuta en cada render.
2️⃣ Con array vacío
useEffect(() => {console.log("Solo una vez");}, []);
Se ejecuta una sola vez (como componentDidMount en componentes de clase).
3️⃣ Con dependencias
useEffect(() => {console.log("Cambio count");}, [count]);
Se ejecuta:
- En el primer render
- Cuando cambia
count
¿Cómo decide React si una dependencia cambió?
Hace comparación superficial (shallow comparison).
Por eso esto es peligroso:
useEffect(() => {...}, [{ name: "Juan" }]);
Ese objeto se crea en cada render → siempre cambia → efecto infinito.
Cleanup: lo que muchos ignoran
useEffect(() => {const id = setInterval(() => {console.log("tick");}, 1000);return () => {clearInterval(id);};}, []);
El cleanup se ejecuta:
- Antes de que el efecto vuelva a correr
- Cuando el componente se desmonta
🔎 Esto previene memory leaks.
Error clásico: dependencias incompletas
useEffect(() => {fetchUser(userId);}, []);
Esto está mal si userId puede cambiar.
La regla es simple:
Si lo usás dentro del efecto, debería estar en las dependencias.
useMemo, Optimización con criterio
useMemo memoriza un valor computado.
const filtered = useMemo(() => {return users.filter(u => u.active);}, [users]);
Sin useMemo, ese cálculo se hace en cada render.
Pero cuidado:
No todo necesita useMemo.
Si el cálculo es barato, la memoización puede ser más costosa que recalcular.
useCallback, Estabilidad de funciones
useCallback memoriza funciones.
const handleClick = useCallback(() => {console.log(count);}, [count]);
¿Para qué sirve?
Cuando pasás funciones a:
- Componentes hijos memoizados
- Dependencias de useEffect
Sin useCallback, cada render crea una nueva referencia → puede disparar renders innecesarios.
useRef, Persistencia sin re-render
useRef guarda un valor mutable que no dispara render.
const inputRef = useRef(null);
Caso DOM:
inputRef.current.focus();
Caso almacenamiento interno:
const renderCount = useRef(0);useEffect(() => {renderCount.current++;});
Sirve para:
- Timers
- Guardar valores anteriores
- Evitar re-renders
useContext, Evitar prop drilling
Permite acceder a un contexto sin pasar props manualmente.
const theme = useContext(ThemeContext);
Pero cuidado:
Cada vez que cambia el valor del provider → todos los consumidores re-renderizan.
🔎 Buena práctica:
Separar contextos grandes en varios pequeños.
Buenas prácticas reales con Hooks
1️⃣ Separar efectos por responsabilidad
Mal:
useEffect(() => {fetchData();document.title = "Users";}, []);
Mejor:
useEffect(() => {fetchData();}, []);useEffect(() => {document.title = "Users";}, []);
2️⃣ No usar useEffect para lógica derivada
Mal:
useEffect(() => {setFullName(first + " " + last);}, [first, last]);
Correcto:
const fullName = first + " " + last;
No todo necesita estado.
3️⃣ Crear custom hooks
Si repetís lógica, extraela:
function useFetch(url) {const [data, setData] = useState(null);useEffect(() => {fetch(url).then(res => res.json()).then(setData);}, [url]);return data;}
Eso mejora:
- Legibilidad
- Reutilización
- Testeo
Mentalidad correcta al usar Hooks
Antes de escribir uno, preguntate:
- ¿Esto es estado o se puede derivar?
- ¿Este efecto sincroniza algo externo?
- ¿Estoy agregando dependencias correctas?
- ¿Estoy optimizando antes de tiempo?
Hooks no son magia.
Son una forma declarativa de manejar:
- Estado
- Ciclo de vida
- Sincronización
Conclusión
Los Hooks no son difíciles.
Lo difícil es entender el modelo mental detrás.
Cuando entendés:
- Cómo React indexa hooks
- Cómo compara dependencias
- Cuándo corre el cleanup
- Qué dispara renders
Dejás de pelearte con React y empezás a diseñar mejor tus componentes.
Community (0)
There are no reflections here yet...