Cómo solucionar el uso excesivo de useEffect por parte de la IA
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.
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.
El síntoma
useEffect se utiliza para calcular valores derivados o sincronizar estado que podría ser un cálculo simple.
"use client";import { useState, useEffect } from "react";
// WRONG — useEffect to compute derived stateexport function CartSummary({ items }: { items: CartItem[] }) { const [total, setTotal] = useState(0);
useEffect(() => { setTotal(items.reduce((sum, item) => sum + item.price * item.qty, 0)); }, [items]);
return <p>Total: ${total}</p>; // Renders twice: once with total=0, once after the effect runs}Un segundo patrón: obtener datos en useEffect cuando un Server Component podría hacerlo sin ningún costo de paquete del cliente.
"use client";useEffect(() => { fetch("/api/products").then((r) => r.json()).then(setProducts);}, []);// Waterfall: page loads -> JS executes -> fetch starts -> renderPor qué ocurre
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.
Cómo detectarlo
useEffectestablece estado que es directamente computable a partir de props u otro estado.useEffect(() => { fetch(...).then(setState) }, [])en la parte superior de un componente que no está dentro de un subárbol de Server Component.useEffectsin limpieza donde la dependencia es una función (riesgo de closure obsoleto).useEffectutilizado únicamente para registro o análisis en el montaje.
Cómo solucionarlo
Usa la herramienta adecuada para cada tarea:
// CORRECT — derived state: just compute itexport function CartSummary({ items }: { items: CartItem[] }) { const total = items.reduce((sum, item) => sum + item.price * item.qty, 0); return <p>Total: ${total.toFixed(2)}</p>;}
// CORRECT — expensive derivation: useMemoimport { useMemo } from "react";
export function FilteredList({ items, query }: { items: Item[]; query: string }) { const filtered = useMemo( () => items.filter((i) => i.name.toLowerCase().includes(query.toLowerCase())), [items, query] ); return <ul>{filtered.map((i) => <li key={i.id}>{i.name}</li>)}</ul>;}// CORRECT — data fetching: async Server Component (no useEffect needed)export default async function ProductsPage() { const products = await fetch("https://api.example.com/products").then((r) => r.json() ); return <ProductList products={products} />;}[ ] Derived values from props/state are plain calculations, not useEffect + setState[ ] Expensive derivations use useMemo, not useEffect[ ] Data fetching on mount moves to async Server Components or React Query/SWR[ ] Event-driven side-effects (form submit, button click) are in event handlers[ ] useEffect is reserved for: external system sync, subscriptions, cleanup[ ] Every useEffect that sets state has a loading/error state and cleanupIndicación de corrección
This component uses useEffect to compute derived state or fetch initial data.Refactor it: replace derived-state effects with direct calculations or useMemo,move initial data fetching to an async Server Component parent or to adata-fetching library (SWR/React Query) with proper loading/error handling, andkeep useEffect only for genuine external-system synchronization that requirescleanup. Explain each useEffect you keep and why it cannot be replaced.Prueba
# Count useEffect calls — a high number is a smell worth reviewinggrep -rn "useEffect" --include="*.tsx" --include="*.ts" src/ app/ \ | grep -v "node_modules" \ | wc -l
# Flag useEffect+setState patterns for manual reviewgrep -A5 "useEffect" app/**/*.tsx 2>/dev/null | grep "setState\|set[A-Z]" \ && echo "REVIEW: possible derived-state antipattern" || echo "OK"