Cómo solucionar el bucle infinito en useEffect con objetos y arrays
Explicación técnica
El problema ocurre porque useEffect compara los valores de las dependencias usando comparación de referencia (===), no por contenido (deep equality). 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), lo que dispara la reejecución del useEffect, causando el bucle infinito.
En tu caso:
const [ingredients, setIngredients] = useState({});
useEffect(() => {
setIngredients({}); // ¡Crea un nuevo objeto!
}, [ingredients]); // ingredients cambia de referencia → reejecuta → loop infinito
Pasos para solucionarlo
Opción 1: Evitar la actualización innecesaria (recomendada)
Si no necesitas actualizar el estado dentro del useEffect, elimina la dependencia del objeto/array y usa un array vacío:
useEffect(() => {
// Solo ejecutar al montar el componente
setIngredients({});
}, []); // ✅ Sin dependencias → solo se ejecuta una vez
Opción 2: Comparación profunda manual
Si necesitas ejecutar el useEffect solo cuando el contenido cambia, usa JSON.stringify (para objetos simples sin funciones/circularidades):
useEffect(() => {
setIngredients({});
}, [JSON.stringify(ingredients)]); // ✅ Compara contenido, no referencia
⚠️ Advertencia: JSON.stringify es costoso en objetos grandes y falla con funciones, undefined, o referencias circulares.
Opción 3: Usar useMemo para una representación estable
Crea una representación estable del objeto (ej. número de elementos, hash):
const ingredientsHash = useMemo(() =>
Object.keys(ingredients).length, // o tu lógica personalizada
[ingredients]
);
useEffect(() => {
setIngredients({});
}, [ingredientsHash]); // ✅ Compara valor primitivo estable
Opción 4: Validar si el valor es distinto antes de actualizar
Evita la actualización si el contenido es idéntico:
useEffect(() => {
if (Object.keys(ingredients).length > 0) {
setIngredients({});
}
}, [ingredients]); // ✅ Solo actualiza si no está vacío
Bloque de código corregido (recomendado)
const [ingredients, setIngredients] = useState({});
useEffect(() => {
// Solo ejecutar al montar el componente (ej. limpiar estado inicial)
setIngredients({});
}, []); // ✅ Solución definitiva para este caso
Pro-tip
- Nunca actualices el mismo estado que usas como dependencia sin una lógica de comparación profunda.
- Para objetos complejos, usa librerías como
immerouseDeepCompareEffect(deuse-deep-compare-effect) si necesitas comparación profunda segura. - Si el objetivo es limpiar el estado al montar, usa
useEffectcon[]y no actualices el estado dentro. En su lugar, inicializa el estado con el valor deseado desde el inicio:
const [ingredients, setIngredients] = useState({}); // ✅ Inicialización directa


















