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.
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.
"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 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.
"use client";useEffect(() => { fetch("/api/products").then((r) => r.json()).then(setProducts);}, []);// Waterfall: page loads -> JS executes -> fetch starts -> renderPourquoi 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
useEffectdé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.useEffectsans nettoyage dont la dépendance est une fonction (risque de fermeture obsolète).useEffectutilisé uniquement pour la journalisation ou l’analyse lors du montage.
Comment le corriger
Utilisez le bon outil pour la tâche :
// 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 cleanupPrompt de correction
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"