# Comment corriger la surutilisation de useEffect par l'IA

> Les agents IA utilisent useEffect pour gérer l'état dérivé, les transformations d'événements et la récupération de données qui devraient plutôt utiliser useMemo, les gestionnaires d'événements ou les Server Components.

**Type:** Failure  
**Tools:** Cursor, Claude Code, Codex, Windsurf  
**Stack:** Next.js, TypeScript  
**Updated:** 2026-06-08

---

L'agent encapsule la logique dans `useEffect` qui devrait être un état dérivé, un gestionnaire d'événements ou une récupération par Server Component — provoquant des rendus supplémentaires, des fermetures obsolètes et des conditions de concurrence.

## Le symptôme

`useEffect` est utilisé pour calculer des valeurs dérivées ou synchroniser un état qui pourrait être un simple calcul.

```tsx
"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
}
```

Un deuxième modèle : récupérer des données dans `useEffect` alors qu'un Server Component pourrait le faire sans aucun coût de bundle client.

```tsx
"use client";
useEffect(() => {
  fetch("/api/products").then((r) => r.json()).then(setProducts);
}, []);
// Waterfall: page loads -> JS executes -> fetch starts -> render
```

## Pourquoi cela se produit

`useEffect` était la principale échappatoire pour les effets de bord dans React 16/17. Les modèles entraînés sur du code pré-React-18 et pré-App-Router ont appris à l'utiliser par défaut. Le modèle mental "J'ai besoin que quelque chose se produise après le rendu" correspond à `useEffect` même lorsque la vraie solution est plus simple.

## Comment le repérer

- `useEffect` définit un état qui est directement calculable à partir des props ou d'un autre état.
- `useEffect(() => { fetch(...).then(setState) }, [])` en haut d'un composant qui n'est pas dans un arbre Server Component.
- `useEffect` sans nettoyage dont la dépendance est une fonction (risque de fermeture obsolète).
- `useEffect` utilisé uniquement pour la journalisation ou l'analyse lors du montage.

## Comment le corriger

Utilisez le bon outil pour la tâche :

```tsx
// 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>;
}
```

```tsx
// CORRECT — data fetching: async Server Component (no useEffect needed)
// app/products/page.tsx
export default async function ProductsPage() {
  const products = await fetch("https://api.example.com/products").then((r) =>
    r.json()
  );
  return <ProductList products={products} />;
}
```

```txt
[ ] 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
```

## Prompt de correction

```txt title="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

```bash
# 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"
```