So beheben Sie die übermäßige Nutzung von useEffect durch KI
KI-Agenten greifen auf useEffect zurück, um abgeleitete Zustände, Ereignistransformationen und Datenabrufe zu behandeln, die stattdessen useMemo, Ereignishandler oder Server Components verwenden sollten.
Der Agent kapselt Logik in useEffect, die eigentlich abgeleiteter Zustand, ein Ereignishandler oder ein Server Component-Fetch sein sollte — was zu zusätzlichen Renderings, veralteten Closures und Race Conditions führt.
Das Symptom
useEffect wird verwendet, um abgeleitete Werte zu berechnen oder Zustand zu synchronisieren, der eine einfache Berechnung sein könnte.
"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}Ein zweites Muster: Datenabruf in useEffect, obwohl eine Server Component dies ohne jegliche Client-Bundle-Kosten erledigen könnte.
"use client";useEffect(() => { fetch("/api/products").then((r) => r.json()).then(setProducts);}, []);// Waterfall: page loads -> JS executes -> fetch starts -> renderWarum es passiert
useEffect war der primäre Side-Effect-Ausweg in React 16/17. Modelle, die mit Code vor React 18 und vor dem App Router trainiert wurden, haben gelernt, standardmäßig darauf zurückzugreifen. Das mentale Modell „Ich brauche etwas, das nach dem Rendern passiert“ wird auf useEffect abgebildet, selbst wenn die eigentliche Lösung einfacher ist.
Wie man es erkennt
useEffectsetzt einen Zustand, der direkt aus Props oder anderem Zustand berechnet werden kann.useEffect(() => { fetch(...).then(setState) }, [])oben in einer Komponente, die sich nicht in einem Server Component-Unterbaum befindet.useEffectohne Bereinigung, bei dem die Abhängigkeit eine Funktion ist (Risiko veralteter Closures).useEffect, das nur zum Loggen oder für Analysen beim Mounten verwendet wird.
Wie man es behebt
Verwenden Sie das richtige Werkzeug für die Aufgabe:
// 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 cleanupFix Prompt
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.Test
# 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"