DEV Community

Erick Eduardo Ramos
Erick Eduardo Ramos

Posted on

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

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

Explicación técnica (por qué ocurre)

El problema ocurre porque useEffect compara los valores de las dependencias usando comparación de referencia (===), no por contenido. 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), por lo que vuelve a ejecutar el efecto, causando el bucle infinito.

En tu caso:

const [ingredients, setIngredients] = useState({});
useEffect(() => {
  setIngredients({}); // ¡Crea un nuevo objeto!
}, [ingredients]); // ingredients cambia de referencia → efecto se vuelve a ejecutar
Enter fullscreen mode Exit fullscreen mode

Pasos para solucionarlo

Opción 1: Evitar la actualización innecesaria (recomendada)

Verifica si el estado ya tiene el valor deseado antes de actualizarlo:

useEffect(() => {
  if (Object.keys(ingredients).length > 0) {
    setIngredients({});
  }
}, [ingredients]);
Enter fullscreen mode Exit fullscreen mode

Opción 2: Usar comparación profunda con useDeepCompareEffect (para casos complejos)

Instala la librería use-deep-compare-effect:

npm install use-deep-compare-effect
Enter fullscreen mode Exit fullscreen mode

Y reemplaza useEffect:

import useDeepCompareEffect from 'use-deep-compare-effect';

useDeepCompareEffect(() => {
  setIngredients({});
}, [ingredients]);
Enter fullscreen mode Exit fullscreen mode

Opción 3: Usar useReducer para lógica de estado compleja

const initialState = {};
function reducer(state, action) {
  switch (action.type) {
    case 'reset':
      return {};
    default:
      return state;
  }
}

const [ingredients, dispatch] = useReducer(reducer, initialState);

useEffect(() => {
  dispatch({ type: 'reset' });
}, [ingredients]);
Enter fullscreen mode Exit fullscreen mode

Opción 4: Normalizar el estado (recomendada para arrays/objetos grandes)

Convierte el objeto/array en un valor primitivo para las dependencias:

const [ingredients, setIngredients] = useState({});
const ingredientsKey = JSON.stringify(ingredients);

useEffect(() => {
  if (ingredientsKey !== '{}') {
    setIngredients({});
  }
}, [ingredientsKey]);
Enter fullscreen mode Exit fullscreen mode

Bloque de código corregido (solución definitiva)

import { useState, useEffect } from 'react';

function Component() {
  const [ingredients, setIngredients] = useState({});

  useEffect(() => {
    // Solo actualiza si no está vacío
    if (Object.keys(ingredients).length > 0) {
      setIngredients({});
    }
  }, [ingredients]);

  return (
    // tu JSX aquí
  );
}
Enter fullscreen mode Exit fullscreen mode

Pro-tip

  • Nunca uses useEffect(() => {}, [obj]) con objetos mutables sin validación previa
  • Para objetos simples, usa JSON.stringify() como dependencia (con cuidado con rendimiento)
  • Para lógica compleja, considera useReducer o librerías como immer para manejar inmutabilidad
  • Si solo necesitas limpiar el estado al montar el componente, usa un array vacío: useEffect(() => { ... }, [])

Top comments (0)