Un effet boucle lorsqu’il modifie un état, que cet état déclenche un rendu, puis qu’une dépendance de l’effet change encore à ce rendu. Le message Maximum update depth exceeded peut en être le symptôme. Deux exécutions au montage en développement ne prouvent pas une boucle : React Strict Mode vérifie aussi le nettoyage des effets.
Reproduire et trouver le cycle
Repérez l’effet qui appelle setState et les valeurs dans son tableau de dépendances. Dans React DevTools, observez quels composants se rendent à répétition. Ajoutez temporairement un journal pour voir la valeur qui change, puis retirez-le une fois le diagnostic terminé.
| Symptôme | Cause à vérifier |
|---|---|
| L’effet tourne après chaque rendu | Tableau de dépendances absent |
| L’effet tourne malgré un tableau | Objet ou fonction recréé à chaque rendu |
| L’effet modifie une de ses dépendances | Mise à jour qui entretient elle-même le cycle |
| Deux appels au montage, puis plus rien | Vérification de Strict Mode en développement |
Supprimer l’effet s’il ne synchronise rien d’externe
Un calcul basé uniquement sur des props ou un état existant peut se faire pendant le rendu :
function Liste({ items, filtre }: { items: string[]; filtre: string }) {
const visibles = items.filter((item) => item.includes(filtre));
return <ul>{visibles.map((item) => <li key={item}>{item}</li>)}</ul>;
}
Stocker aussi visibles dans un état, puis le recalculer dans un effet, ajoute un rendu et deux valeurs à maintenir cohérentes. Une optimisation avec useMemo ne devient utile que si le calcul est coûteux et mesuré.
Stabiliser une vraie dépendance
Ici, options est un nouvel objet à chaque rendu. Si l’effet met à jour un état utilisé par le composant, cela peut provoquer des relances inutiles :
// À éviter : l'objet change d'identité à chaque rendu.
const options = { roomId };
useEffect(() => {
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, [options]);
Pour un système externe comme une connexion, construisez l’objet dans l’effet et dépendez de la valeur primitive réellement utilisée :
useEffect(() => {
const connection = createConnection({ roomId });
connection.connect();
return () => connection.disconnect();
}, [roomId]);
Cet extrait suppose que createConnection existe dans votre application. Ne retirez pas roomId du tableau pour faire taire le lint : l’effet doit se reconnecter quand cette valeur change. Le nettoyage est nécessaire lorsque le composant se démonte ou que roomId change.
Vérifier une mise à jour d’état intentionnelle
Si l’effet reçoit des données externes, demandez-vous si la mise à jour produit réellement une nouvelle valeur. Une mise à jour répétée avec un objet neuf, même de contenu identique, peut entretenir des rendus. Comparez la donnée utile avant de mettre à jour l’état ou déplacez la transformation dans le calcul de rendu.
Ne remplacez pas automatiquement une dépendance par []. Cela peut laisser l’effet connecté à d’anciennes props. useCallback et useMemo peuvent stabiliser certaines références, mais commencez par simplifier la logique et déplacer les objets temporaires dans l’effet.
Confirmer la correction
Testez le montage, un changement réel de dépendance et le démontage. Vérifiez que l’effet s’exécute quand il le doit, que son nettoyage fonctionne et que le rendu ne se répète plus sans raison. En développement sous Strict Mode, un cycle supplémentaire de configuration et nettoyage au montage reste normal.

