惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
G
Google Developers Blog
L
LangChain Blog
Y
Y Combinator Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
大猫的无限游戏
大猫的无限游戏
博客园 - Franky
V
Visual Studio Blog
小众软件
小众软件
月光博客
月光博客
A
About on SuperTechFans
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
The Blog of Author Tim Ferriss
有赞技术团队
有赞技术团队
M
MIT News - Artificial intelligence
阮一峰的网络日志
阮一峰的网络日志
Last Week in AI
Last Week in AI
博客园 - 【当耐特】
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
MongoDB | Blog
MongoDB | Blog
Jina AI
Jina AI
美团技术团队
量子位

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Cómo solucionar el bucle infinito en useEffect con objeto...
Erick Eduard · 2026-05-22 · via DEV Community

Erick Eduardo Ramos

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

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

El problema ocurre porque React compara las dependencias del useEffect usando comparación === (igualdad estricta), no por contenido (deep equality). Cuando usas useState({}), cada llamada a setObj({}) crea un nuevo objeto en memoria, aunque tenga el mismo contenido. Por lo tanto:

  • [obj] como dependencia → React compara obj1 === obj2 → siempre false
  • Esto dispara el useEffect infinitamente → actualiza estado → re-renders → nuevo objeto → efecto se dispara de nuevo

Este comportamiento es intencional en React para evitar costosas comparaciones profundas por defecto.


Pasos para solucionarlo

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

No vuelvas a establecer el mismo valor si no es necesario. Usa una condición para evitar la actualización:

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

Enter fullscreen mode Exit fullscreen mode

Opción 2: Usar comparación profunda manual (cuando necesitas reaccionar a cambios específicos)

Implementa una comparación profunda con JSON.stringify (solo para objetos simples sin funciones/circularidades):

useEffect(() => {
  const prev = JSON.stringify(ingredients);
  // Simula comparación profunda
  if (prev !== JSON.stringify({})) {
    setIngredients({});
  }
}, [ingredients]);

Enter fullscreen mode Exit fullscreen mode

Opción 3: Usar useMemo para crear una referencia estable (patrón avanzado)

Si necesitas mantener una referencia estable para evitar re-renders:

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

useEffect(() => {
  setIngredients(emptyIngredients);
}, [emptyIngredients]);

Enter fullscreen mode Exit fullscreen mode

Opción 4: Separar dependencias (patrón más limpio)

Divide el estado en valores primitivos cuando sea posible:

const [count, setCount] = useState(0);
const [list, setList] = useState([]);

useEffect(() => {
  if (count > 0 || list.length > 0) {
    setCount(0);
    setList([]);
  }
}, [count, list]);

Enter fullscreen mode Exit fullscreen mode


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

Caso de uso típico: limpiar estado al montar el componente

import { useState, useEffect } from 'react';

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

  useEffect(() => {
    // Inicializa con valores por defecto solo al montar
    setIngredients({});
  }, []); // ← Dependencia vacía: solo se ejecuta una vez

  return (
    <div>
      <pre>{JSON.stringify(ingredients, null, 2)}</pre>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Caso de uso: limpiar estado cuando cambia una condición específica

useEffect(() => {
  // Solo limpiar si hay datos
  if (Object.keys(ingredients).length > 0) {
    setIngredients({});
  }
}, [ingredients]);

Enter fullscreen mode Exit fullscreen mode


Pro-tip: Buenas prácticas con objetos y arrays en hooks

  1. Nunca uses objetos/array literales como dependencias ([{}], [{...}])
  2. Para comparaciones profundas, usa librerías como fast-deep-equal
   import deepEqual from 'fast-deep-equal';

   useEffect(() => {
     if (!deepEqual(ingredients, {})) {
       setIngredients({});
     }
   }, [ingredients]);

Enter fullscreen mode Exit fullscreen mode

  1. Considera usar useReducer para estados complejos
   const initialState = { ingredients: {} };
   const reducer = (state, action) => {
     switch (action.type) {
       case 'reset': return { ...state, ingredients: {} };
       default: return state;
     }
   };

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

Enter fullscreen mode Exit fullscreen mode

  1. Siempre pregunta: ¿realmente necesito este useEffect? Muchas veces la lógica puede moverse a eventos directos (onClick, onChange)

⚠️ Advertencia crítica: JSON.stringify es costoso en rendimiento. Úsalo solo para objetos pequeños y nunca en componentes que rendericen frecuentemente.