Cómo solucionar el bucle infinito en useEffect con objetos y arrays en React
Explicación técnica
El problema ocurre porque useEffect compara los valores de las dependencias usando comparación de referencia (===), no por contenido (shallow comparison). Cuando usas useState({}), cada llamada a setObj({}) crea un nuevo objeto en memoria, aunque tenga el mismo contenido. React detecta que la referencia cambia (obj !== obj) y vuelve a ejecutar el efecto, causando el bucle infinito.
En tu caso:
const [obj, setObj] = useState({});
useEffect(() => {
setObj({}); // ← ¡Nuevo objeto en memoria!
}, [obj]); // ← Referencia diferente → re-ejecuta efecto
Pasos para solucionarlo
Opción 1: Evitar la actualización innecesaria (recomendada)
useEffect(() => {
// Solo actualiza si realmente hay un cambio de estado
setObj(prev => {
// Si ya está vacío, no hagas nada
if (Object.keys(prev).length === 0) return prev;
return {};
});
}, []); // ← Sin dependencias: solo ejecuta al montar
Opción 2: Usar comparación profunda manual
import { useEffect, useState, useRef } from 'react';
const [obj, setObj] = useState({});
const prevObjRef = useRef();
useEffect(() => {
// Comparación profunda manual
const hasChanged = JSON.stringify(obj) !== JSON.stringify(prevObjRef.current);
if (hasChanged) {
setObj({}); // O la lógica que necesites
prevObjRef.current = obj;
}
}, [obj]);
Opción 3: Usar useMemo para mantener la misma referencia
const emptyObj = useMemo(() => ({}), []);
useEffect(() => {
setObj(emptyObj);
}, [emptyObj]);
Bloque de código corregido (solución definitiva)
import { useState, useEffect, useCallback } from 'react';
function Component() {
const [ingredients, setIngredients] = useState({});
// Solución limpia: solo ejecutar efecto al montar
useEffect(() => {
// Tu lógica de inicialización aquí
// Si necesitas resetear, hazlo solo una vez
setIngredients({});
}, []); // ← Dependencia vacía: ejecuta una sola vez
// Alternativa: función memoizada para evitar re-renders
const resetIngredients = useCallback(() => {
setIngredients({});
}, []);
return (
// Tu JSX
);
}
Pro-tip
-
Nunca uses objetos/arrays literales como dependencias directas (
[{}],[obj]dondeobjse redefine en cada render). - Usa
useCallbackpara funciones yuseMemopara valores complejos que necesitas como dependencias. - Para objetos/arrays grandes, considera usar librerías como
fast-deep-equaloreact-fast-comparepara comparaciones eficientes. - Si solo necesitas ejecutar efectos una vez (como inicialización), siempre usa
[]como dependencia.
Top comments (0)