Le WordPress d'aujourd'hui, décodé pour les développeurs

Blocs Gutenberg

« Too many re-renders » : un useEffect mal cadré boucle dans un bloc

L'éditeur se fige et la console répète « Too many re-renders. React limits the number of renders » : un useEffect sans dépendance correcte tourne en boucle infinie.

Par WordPress Développement • 29 octobre 2023 • 4 min de lecture • Aucun commentaire
« Too many re-renders » : un useEffect mal cadré boucle dans un bloc

« Too many re-renders. React limits the number of renders to prevent an infinite loop. » Ce message, affiché dans la console du navigateur, accompagné d’un éditeur totalement figé ou d’un onglet qui consomme le processeur à pleine charge, signale presque toujours la même cause : un appel à setAttributes déclenché sans condition suffisante à l’intérieur d’un useEffect, lui-même redéclenché par le changement qu’il vient de provoquer.

Symptôme

Le bloc concerné, une fois inséré dans l’éditeur, provoque un blocage quasi immédiat de l’interface. Le message d’erreur mentionné apparaît dans la console, parfois précédé de plusieurs centaines de lignes de rendu successives visibles dans les outils de développement React si l’extension est installée. Dans les cas moins francs, aucun message n’apparaît, mais l’éditeur devient perceptiblement plus lent à chaque insertion du bloc, signe d’une boucle qui se stabilise sans dépasser la limite stricte de React mais consomme malgré tout des cycles de rendu inutiles.

Diagnostic

Le code fautif ressemble presque toujours à ceci :

useEffect( () => {
	setAttributes( { largeurCalculee: largeurConteneur * ratio } );
} ); // pas de tableau de dépendances : exécuté à chaque rendu

Sans tableau de dépendances, l’effet s’exécute après chaque rendu du composant. Comme il appelle setAttributes, qui déclenche lui-même un nouveau rendu, la boucle se referme immédiatement : rendu, effet, mise à jour d’attribut, nouveau rendu, et ainsi de suite sans jamais s’arrêter. Même avec un tableau de dépendances présent, le problème persiste si la valeur recalculée à l’intérieur de l’effet est elle-même l’une de ses propres dépendances, ou si un objet ou tableau recréé à chaque rendu (donc jamais strictement égal au précédent) figure dans ce tableau.

Vérifier la vraie source de la boucle

Pour confirmer le diagnostic sans deviner, un simple console.log placé au tout début du composant Edit, affichant un compteur incrémenté à chaque montage, permet de mesurer objectivement la fréquence des rendus avant de conclure. Une boucle réelle produit des dizaines, voire des centaines d’appels en quelques secondes, alors qu’un rendu normal, même redondant, reste limité à quelques occurrences.

L'essentiel à retenir : Le symptôme est presque toujours un setAttributes hors condition ; Le tableau de dépendances de useEffect est la première chose à vérifier ; Une correction robuste évite aussi la boucle silencieuse sans message d'erreur

Correctif

La correction la plus directe consiste à déclarer un tableau de dépendances précis, limité aux valeurs qui doivent réellement déclencher le recalcul, et à comparer la nouvelle valeur à l’ancienne avant d’appeler setAttributes :

useEffect( () => {
	const largeurRecalculee = largeurConteneur * ratio;

	if ( largeurRecalculee !== attributes.largeurCalculee ) {
		setAttributes( { largeurCalculee: largeurRecalculee } );
	}
}, [ largeurConteneur, ratio ] );

Le tableau de dépendances limite les déclenchements aux seuls changements pertinents (largeurConteneur et ratio), et la comparaison explicite empêche setAttributes d’être appelé lorsque la valeur calculée est identique à celle déjà stockée, ce qui coupe définitivement la boucle même si l’effet venait à se redéclencher pour une autre raison.

Prévention

  • Ne jamais écrire un useEffect qui appelle setAttributes sans avoir explicitement réfléchi à son tableau de dépendances.
  • Comparer systématiquement l’ancienne et la nouvelle valeur avant d’écrire, dès qu’un effet peut potentiellement se redéclencher lui-même.
  • Préférer, quand c’est possible, un calcul dérivé directement dans le rendu (sans useEffect ni setAttributes) plutôt que de stocker une valeur qui peut être recalculée à la volée.

La question à se poser avant d’écrire un useEffect dans un bloc : cette valeur a-t-elle vraiment besoin d’être stockée en attribut, ou peut-elle simplement être calculée à chaque rendu sans passer par un effet ? La seconde option supprime le risque de boucle par construction.

Le cas particulier de la synchronisation avec une donnée externe

Ce type de boucle apparaît fréquemment lorsqu’un bloc synchronise un attribut avec une donnée qui change de source (une réponse d’API, une mesure du DOM via une référence). Dans ce cas, le tableau de dépendances doit inclure la source réelle du changement (la référence, la donnée d’API), jamais l’attribut lui-même dérivé de cette source, sous peine de recréer exactement la même boucle sous une forme légèrement différente.

En résumé

« Too many re-renders » désigne presque toujours un setAttributes déclenché sans condition suffisante à l’intérieur d’un effet qui se redéclenche lui-même. Un tableau de dépendances précis et une comparaison explicite de la valeur avant écriture suffisent, dans l’immense majorité des cas, à retrouver un bloc stable et un éditeur réactif.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi