{
  "id": "ai-overuses-useeffect",
  "type": "failures",
  "category": "failures",
  "locale": "es",
  "url": "/es/failures/ai-overuses-useeffect",
  "title": "Cómo solucionar el uso excesivo de useEffect por parte de la IA",
  "description": "Los agentes de IA recurren a useEffect para manejar estado derivado, transformaciones de eventos y obtención de datos que en su lugar deberían usar useMemo, manejadores de eventos o Server Components.",
  "tools": [
    "Cursor",
    "Claude Code",
    "Codex",
    "Windsurf"
  ],
  "stack": [
    "Next.js",
    "TypeScript"
  ],
  "tags": [
    "react",
    "nextjs",
    "hydration"
  ],
  "difficulty": null,
  "updated": "2026-06-08",
  "markdown": "El agente envuelve lógica en `useEffect` que debería ser estado derivado, un manejador de eventos o una obtención de datos de Server Component, lo que provoca renderizados adicionales, closures obsoletos y condiciones de carrera.\n\n## El síntoma\n\n`useEffect` se utiliza para calcular valores derivados o sincronizar estado que podría ser un cálculo simple.\n\n```tsx\n\"use client\";\nimport { useState, useEffect } from \"react\";\n\n// WRONG — useEffect to compute derived state\nexport function CartSummary({ items }: { items: CartItem[] }) {\n  const [total, setTotal] = useState(0);\n\n  useEffect(() => {\n    setTotal(items.reduce((sum, item) => sum + item.price * item.qty, 0));\n  }, [items]);\n\n  return <p>Total: ${total}</p>;\n  // Renders twice: once with total=0, once after the effect runs\n}\n```\n\nUn segundo patrón: obtener datos en `useEffect` cuando un Server Component podría hacerlo sin ningún costo de paquete del cliente.\n\n```tsx\n\"use client\";\nuseEffect(() => {\n  fetch(\"/api/products\").then((r) => r.json()).then(setProducts);\n}, []);\n// Waterfall: page loads -> JS executes -> fetch starts -> render\n```\n\n## Por qué ocurre\n\n`useEffect` era la puerta de escape principal para efectos secundarios en React 16/17. Los modelos entrenados con código anterior a React 18 y a App Router aprendieron a recurrir a él por defecto. El modelo mental \\\"necesito que algo suceda después del renderizado\\\" se asigna a `useEffect` incluso cuando la solución real es más simple.\n\n## Cómo detectarlo\n\n- `useEffect` establece estado que es directamente computable a partir de props u otro estado.\n- `useEffect(() => { fetch(...).then(setState) }, [])` en la parte superior de un componente que no está dentro de un subárbol de Server Component.\n- `useEffect` sin limpieza donde la dependencia es una función (riesgo de closure obsoleto).\n- `useEffect` utilizado únicamente para registro o análisis en el montaje.\n\n## Cómo solucionarlo\n\nUsa la herramienta adecuada para cada tarea:\n\n```tsx\n// CORRECT — derived state: just compute it\nexport function CartSummary({ items }: { items: CartItem[] }) {\n  const total = items.reduce((sum, item) => sum + item.price * item.qty, 0);\n  return <p>Total: ${total.toFixed(2)}</p>;\n}\n\n// CORRECT — expensive derivation: useMemo\nimport { useMemo } from \"react\";\n\nexport function FilteredList({ items, query }: { items: Item[]; query: string }) {\n  const filtered = useMemo(\n    () => items.filter((i) => i.name.toLowerCase().includes(query.toLowerCase())),\n    [items, query]\n  );\n  return <ul>{filtered.map((i) => <li key={i.id}>{i.name}</li>)}</ul>;\n}\n```\n\n```tsx\n// CORRECT — data fetching: async Server Component (no useEffect needed)\n// app/products/page.tsx\nexport default async function ProductsPage() {\n  const products = await fetch(\"https://api.example.com/products\").then((r) =>\n    r.json()\n  );\n  return <ProductList products={products} />;\n}\n```\n\n```txt\n[ ] Derived values from props/state are plain calculations, not useEffect + setState\n[ ] Expensive derivations use useMemo, not useEffect\n[ ] Data fetching on mount moves to async Server Components or React Query/SWR\n[ ] Event-driven side-effects (form submit, button click) are in event handlers\n[ ] useEffect is reserved for: external system sync, subscriptions, cleanup\n[ ] Every useEffect that sets state has a loading/error state and cleanup\n```\n\n## Indicación de corrección\n\n```txt title=\"Fix Prompt\"\nThis component uses useEffect to compute derived state or fetch initial data.\nRefactor it: replace derived-state effects with direct calculations or useMemo,\nmove initial data fetching to an async Server Component parent or to a\ndata-fetching library (SWR/React Query) with proper loading/error handling, and\nkeep useEffect only for genuine external-system synchronization that requires\ncleanup. Explain each useEffect you keep and why it cannot be replaced.\n```\n\n## Prueba\n\n```bash\n# Count useEffect calls — a high number is a smell worth reviewing\ngrep -rn \"useEffect\" --include=\"*.tsx\" --include=\"*.ts\" src/ app/ \\\n  | grep -v \"node_modules\" \\\n  | wc -l\n\n# Flag useEffect+setState patterns for manual review\ngrep -A5 \"useEffect\" app/**/*.tsx 2>/dev/null | grep \"setState\\|set[A-Z]\" \\\n  && echo \"REVIEW: possible derived-state antipattern\" || echo \"OK\"\n```"
}