DEV Community

Erick Eduardo Ramos
Erick Eduardo Ramos

Posted on

Cómo solucionar el bucle infinito en useEffect con objetos y arrays en React

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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]);
Enter fullscreen mode Exit fullscreen mode

Opción 3: Usar useMemo para mantener la misma referencia

const emptyObj = useMemo(() => ({}), []);

useEffect(() => {
  setObj(emptyObj);
}, [emptyObj]);
Enter fullscreen mode Exit fullscreen mode

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
  );
}
Enter fullscreen mode Exit fullscreen mode

Pro-tip

  • Nunca uses objetos/arrays literales como dependencias directas ([{}], [obj] donde obj se redefine en cada render).
  • Usa useCallback para funciones y useMemo para valores complejos que necesitas como dependencias.
  • Para objetos/arrays grandes, considera usar librerías como fast-deep-equal o react-fast-compare para comparaciones eficientes.
  • Si solo necesitas ejecutar efectos una vez (como inicialización), siempre usa [] como dependencia.

Top comments (0)