P PasteCode
Fehlschlag

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.

CursorClaude CodeCodexWindsurf Next.jsTypeScript
.md .json Aktualisiert 8. Juni 2026

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 state
export 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 -> render

Warum 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

  • useEffect setzt 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.
  • useEffect ohne 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 it
export 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: useMemo
import { 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>;
}
app/products/page.tsx
// 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 cleanup

Fix Prompt

Fix 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 a
data-fetching library (SWR/React Query) with proper loading/error handling, and
keep useEffect only for genuine external-system synchronization that requires
cleanup. Explain each useEffect you keep and why it cannot be replaced.

Test

Terminal window
# Count useEffect calls — a high number is a smell worth reviewing
grep -rn "useEffect" --include="*.tsx" --include="*.ts" src/ app/ \
| grep -v "node_modules" \
| wc -l
# Flag useEffect+setState patterns for manual review
grep -A5 "useEffect" app/**/*.tsx 2>/dev/null | grep "setState\|set[A-Z]" \
&& echo "REVIEW: possible derived-state antipattern" || echo "OK"