- useState et useEffect concentrent la plupart des états et des effets secondaires des composants fonctionnels de React, remplaçant ainsi de nombreuses méthodes de cycle de vie classiques.
- Un effet peut inclure une logique de nettoyage renvoyant une fonction, vous permettant de gérer les abonnements, les intervalles et autres ressources externes sans fuites de mémoire.
- Le tableau de dépendances contrôle le moment d'exécution de chaque effet et doit contenir toutes les valeurs réactives utilisées, assurant ainsi un équilibre entre exactitude et performance.
- La séparation de la logique en plusieurs petits effets d'utilisation par responsabilité améliore la lisibilité, facilite la réutilisation et réduit les erreurs courantes telles que les rendus infinis ou les dépendances incorrectes.

Si vous travaillez quotidiennement avec React, la maîtrise de useState et useEffect n'est pas facultative.C'est devenu quasiment une pratique courante. Ces deux Hooks gèrent la majeure partie de la logique d'état et d'effets secondaires de toute application moderne, qu'il s'agisse d'un simple compteur ou d'interfaces complexes avec des requêtes HTTP, des abonnements à des événements et des animations.
Le problème, c'est qu'il est très facile de les utiliser « à l'œil » et de se retrouver avec des fuites de mémoire, des rendus sans fin ou des effets qui se déclenchent alors qu'ils ne le devraient pas.Dans cet article, nous allons décortiquer calmement comment utiliser correctement useState et, surtout, useEffect : ce que cela fait exactement, comment cela se rapporte au cycle de vie du composant, comment gérer les nettoyages, comment optimiser les performances avec le tableau de dépendances et comment appliquer des modèles avancés sans se casser la tête.
Que sont les Hooks et pourquoi useState et useEffect sont-ils si importants ?
Les Hooks sont apparus dans React 16.8 pour permettre l'utilisation de l'état et d'autres fonctionnalités sans avoir besoin de classes.Au lieu de s'étendre à partir de React.Component et en ce qui concerne les méthodes de cycle de vie, nous travaillons avec des fonctions qui appellent des Hooks comme useState y useEffect à l'intérieur.
useState est le Hook qui vous permet d'obtenir un état local au sein d'un composant fonctionnel.Elle renvoie une valeur et une fonction pour la mettre à jour. Chaque modification de cet état déclenche un nouveau rendu du composant. C'est la base pour rendre votre interface dynamique : compteurs, formulaires, indicateurs de chargement, etc.
useEffect, en revanche, est le Hook qui vous permet d'exécuter des effets secondaires après le rendu.Cela inclut des éléments tels que les requêtes de données, les abonnements WebSocket, les écouteurs DOM, les minuteurs, l'intégration avec des bibliothèques externes ou les mises à jour manuelles du DOM lorsqu'il n'y a pas d'autre option.
Si vous venez du monde des composants de classe, vous pouvez considérer useEffect comme la combinaison de componentDidMount, componentDidUpdate et componentWillUnmount.mais intégrée dans une API déclarative unique. L'idée est de raisonner en termes d'« effets qui se produisent après le rendu » plutôt qu'en phases d'« assemblage » ou de « mise à jour » distinctes.
Comment useEffect fonctionne au niveau conceptuel
La signature useEffect de base est très simple : useEffect(configuración, dependencias?)Vous lui transmettez une fonction de configuration qui s'exécutera après le rendu du composant et, éventuellement, une liste de dépendances qui détermine quand cet effet doit être répété.
La fonction de configuration concentre la logique de votre effet : s’abonner à quelque chose, lancer une requête, démarrer un intervalle, interagir avec le DOM, etc. Cette fonction peut également renvoyer une autre fonction de nettoyage que React exécutera lorsqu'il sera temps d'annuler ce que vous avez fait : annuler un intervalle de temps, se désabonner, abandonner une requête, etc.
Le deuxième argument de useEffect est le fameux tableau de dépendancesVous devez y lister toutes les valeurs « réactives » utilisées dans l'effet : les props, l'état et toutes les variables ou fonctions définies directement dans le corps du composant. React compare ce tableau avec celui du rendu précédent. Object.isEn cas de modification d'une dépendance, supprimez l'ancien effet et exécutez le nouveau.
Si vous ne fournissez pas de tableau de dépendances, useEffect est exécuté après chaque rendu.Si vous transmettez un tableau vide []Cet effet n'est exécuté qu'une seule fois lors du montage et est effacé lors du démontage, simulant ainsi le couple. componentDidMount / componentWillUnmountEt si vous transmettez des dépendances spécifiques, l'effet ne se déclenche que lorsqu'une de ces valeurs change.
Premiers pas : combiner useState et useEffect
Un exemple classique pour comprendre la relation entre les deux Hooks est le compteur typique qui met à jour le titre du document.. avec useState Vous gérez le nombre de clics, et avec useEffect vous changez document.title après chaque rendu :
L'essentiel est que useEffect soit défini au sein du composant.Par conséquent, grâce aux fermetures JavaScript, vous pouvez lire directement l'état actuel et les propriétés. Nul besoin d'API React spécifiques pour accéder à l'état au sein de l'effet : tout se trouve dans la portée de la fonction.
De plus, React ne réutilise pas la même fonction d'effet entre les rendus : vous générez une nouvelle fonction à chaque rendu.C'est intentionnel : chaque effet est associé au rendu dans lequel il a été créé, et lorsque React détecte des changements de dépendances, il remplace un effet par un autre, en supprimant d'abord le précédent. Ce modèle permet de mieux comprendre les valeurs que chaque effet reçoit à un instant donné.
Autre détail important : les effets n’empêchent pas le rendu de l’interface.React met d'abord à jour le DOM et laisse le navigateur effectuer le rendu, puis exécute useEffectDans la plupart des cas (demandes, journauxetc.) Cela améliore la sensation de fluidité. Si vous devez effectuer une action synchrone juste avant que l'utilisateur ne voie l'écran (par exemple, mesurer et repositionner une infobulle), vous devriez utiliser useLayoutEffect, qui partage la même API mais s'exécute avant le rendu.
Types d'effets : avec et sans nettoyage
Tous les effets secondaires ne se valent pas : certains s’exécutent et c’est tout, tandis que d’autres nécessitent un nettoyage explicite.Il est essentiel de faire la distinction entre ces deux types pour éviter de laisser des choses non résolues dans la mémoire ou des comportements étranges.
Les effets « no-clean » sont ceux où l'on ne laisse rien « ouvert ».Par exemple, écrire dans le journal, effectuer une requête ponctuelle et enregistrer le résultat dans l'état, lancer une animation automatique ou effectuer une modification ponctuelle du DOM. En termes de cycle de vie, ils dépendent uniquement de componentDidMount / componentDidUpdate et ils n'exigent rien dans componentWillUnmount.
Un exemple typique serait d'utiliser navigator.geolocation.getCurrentPosition une fois le composant renduVous demandez la localisation, mettez à jour l'état avec la latitude et la longitude, React effectue un nouveau rendu, et c'est tout. Aucun écouteur permanent n'est laissé en place, vous n'avez donc rien à nettoyer lors du démontage du composant.
Les effets de nettoyage apparaissent lorsque votre composant est connecté en permanence à un système externe.Cela inclut les abonnements à des websockets ou à une API de chat, les écouteurs d'événements DOM, les intervalles répétitifs ou les délais d'expiration, etc. Dans ces cas, si vous ne nettoyez pas lors du démontage ou de la modification des dépendances, vous risquez de rencontrer des fuites de mémoire ou un comportement inattendu.
La méthode standard de React pour gérer ce nettoyage consiste à renvoyer une fonction à partir de l'effet.Cette fonction s'exécutera chaque fois que l'effet devra être « démonté » : lorsque le composant est supprimé du DOM ou lorsque les dépendances changent et que l'ancien effet doit être remplacé par le nouveau. Un exemple typique est un compteur. setInterval qui est nettoyé avec clearInterval dans le retour de l'effet.
useEffect appliqué aux événements et abonnements globaux
L'utilisation très courante de useEffect consiste à s'abonner aux événements globaux du navigateur.Comme resize de window o keydown de documentDans ces cas-là, vous devez vous connecter à l'événement lors de la configuration du composant et vous déconnecter lors de son démontage afin d'éviter l'accumulation d'écouteurs.
Le schéma est toujours le même : vous ajoutez les écouteurs dans l’effet et vous les supprimez dans la fonction de nettoyage.De plus, si vous souhaitez que cet abonnement ne soit créé qu'une seule fois, vous devez transmettre un tableau de dépendances vide. [] pour que cela ne se répète pas à chaque rendu.
Cette même approche s'applique aux intégrations avec des API externes, des SDK tiers ou tout système qui vous oblige à vous « connecter » lorsque le composant est visible.Vous vous connectez dans la fonction de configuration de l'effet et vous vous déconnectez dans la fonction de nettoyage, en faisant confiance à React pour appeler les deux en fonction des besoins et des changements de dépendances.
En mode développement et en mode strict, React effectue une étape supplémentaire de configuration et de nettoyage juste après le montage.Il s'agit d'un test de résistance permettant de vérifier que votre logique de nettoyage annule bien toutes les modifications apportées par la configuration. Si vous constatez un comportement anormal uniquement en développement, c'est généralement parce que votre nettoyage est insuffisant.
Requêtes HTTP et conditions de concurrence avec useEffect
Un autre scénario très courant pour useEffect consiste à effectuer des requêtes HTTP lorsqu'une propriété ou une partie de l'état change.Par exemple, charger les données d'un utilisateur lorsqu'elles changent userId ou récupérer des informations sur un Pokémon lorsque son nom dans les accessoires est mis à jour.
L'idée générale est la suivante : vous définissez un effet qui déclenche une fonction asynchrone, vous mettez à jour l'état avec les données reçues et vous spécifiez dans le tableau de dépendances les valeurs dont dépend cette requête.Si vous souhaitez qu'il ne se déclenche que lorsque vous roulez, ignorez cette étape. []Si vous voulez qu'il s'exécute à chaque changement userId, vous incluez userId dans le tableau.
Un détail délicat concerne ce qui se passe si le composant est supprimé avant que la requête ne réponde.. Oui dans le then ou après le await appel à setState Concernant un composant qui n'est plus monté, vous pouvez recevoir des avertissements ou, pire encore, des mises à jour d'état concernant des composants zombies.
Une méthode courante pour éviter cela consiste à utiliser un indicateur interne (par exemple, isMounted o ignore)Vous le définissez dans l'effet, vous le mettez à trueet dans la fonction de nettoyage, vous la configurez à false. Dans la fonction asynchrone, juste avant d'appeler setState, vous vérifiez si le drapeau est toujours allumé trueSi c'est déjà le cas falseVous ignorez la mise à jour. Cela permet également d'éviter les conflits d'accès lorsque plusieurs requêtes peuvent être résolues dans un ordre différent de celui de leur soumission.
Une autre option plus moderne consiste à utiliser AbortController si l'API que vous utilisez le prend en charge.afin que la fonction de nettoyage appelle abort() et la promesse de la requête est rejetée sans tentative d'influence sur l'État. En tout état de cause, la logique d'annulation ou d'ignorance des réponses doit être inhérente à l'effet lui-même.
Plusieurs appels à useEffect dans le même composant
L'un des avantages des Hooks est qu'ils permettent de séparer la logique en fonction de sa fonction, et non en fonction de la méthode de cycle de vie dans laquelle elle doit être placée.Il n'y a aucune limitation lors de l'utilisation de plusieurs useEffect dans le même composant.
Cela signifie que vous pouvez avoir un effet pour gérer le titre du document, un autre pour vous abonner à une conversation et un autre pour écouter un événement de défilement.Chacune ayant ses propres dépendances et sa propre logique de nettoyage, React les exécutera toutes dans l'ordre où elles apparaissent dans le composant.
Contrairement aux classes, où de nombreuses logiques sans rapport entre elles finissaient par se retrouver mélangées dans les mêmes méthodes de cycle de vie, les Hooks vous incitent à répartir les responsabilités.Un effet = un objectif précis. Si un effet commence à avoir plusieurs fonctions différentes, il est probablement temps de le scinder en plusieurs.
Ce modèle devient encore plus puissant lorsque vous encapsulez ces effets dans des hooks personnalisés. (par exemple, useWindowSize, useChatStatusetc.), mais même sans aller aussi loin, vous gagnez en lisibilité en utilisant plusieurs petits effets au lieu d'un seul gigantesque.
L'ensemble des dépendances : réactivité et performance
La multitude de dépendances est à la fois ce qui fait la puissance d'useEffect et la source de nombreux maux de tête.La règle générale est simple : toute valeur réactive utilisée dans l’effet doit figurer dans ce tableau. Les valeurs réactives sont les props, l’état et les variables ou fonctions définies dans le composant.
Il ne s'agit pas de « choisir » des dépendances pour que l'effet s'exécute moins longtemps, mais de décrire honnêtement les valeurs dont dépend la logique de l'effet.Si le linter de eslint-plugin-react-hooks Il est correctement configuré ; il vous alertera si vous avez omis quelque chose ou ajouté un élément inutile.
Pour supprimer une dépendance, il ne suffit pas de faire taire l'avertissement ; il faut modifier le code pour que la valeur ne soit plus réactive.Par exemple, si vous utilisez une constante serverUrl Puisqu'elle ne change jamais, vous pouvez la déplacer en dehors du corps du composant. Ainsi, elle cesse d'être une valeur réactive et vous pouvez la supprimer du tableau sans induire React en erreur.
Lorsqu'un effet lit une valeur réactive, on souhaite généralement qu'il réagisse à ses changements.Cela signifie l'ajouter au tableau. Mais parfois, on souhaite lire la valeur « actuelle » d'un élément (comme un panier d'achat) sans que les modifications apportées à cet élément ne déclenchent à nouveau l'effet. Pour ces cas-là, React introduit le concept d'« événements d'effet » (comme useEffectEvent), qui encapsulent du code non réactif capable de lire la dernière valeur sans devenir une dépendance.
Pour améliorer les performances, la méthode classique consiste à réduire le tableau de dépendances au strict minimum.Au lieu de laisser l'effet sans second argument (ce qui le déclenche après chaque rendu), vous transmettez un tableau contenant uniquement les valeurs qui doivent effectivement le déclencher. Si aucune dépendance ne change entre deux rendus, React ignore le nettoyage et la configuration, et l'effet n'est pas réexécuté.
Résolution des problèmes courants liés à useEffect
L'une des erreurs les plus fréquentes consiste à se retrouver avec un effet qui s'exécute en boucle infinie.Cela se produit généralement lorsqu'on met à jour un état au sein même de l'effet, un état faisant partie du tableau de dépendances. L'effet modifie l'état, ce qui déclenche un rendu, le rendu réexécute l'effet, et le cycle recommence.
Pour sortir de cette boucle, examinez pourquoi vous mettez à jour cet état à partir de l'effet.Si vous n'utilisez pas de synchronisation avec un système externe, l'utilisation de `useEffect` est peut-être superflue : de nombreux éléments peuvent être gérés directement lors du rendu. En cas de synchronisation avec un système externe, veillez à ce que la mise à jour de l'état ne dépende que des modifications réelles et ne se déclenche pas systématiquement.
Une autre source fréquente de problèmes réside dans les dépendances qui changent à chaque rendu sans que vous vous en aperceviez.Créer des objets ou des fonctions en ligne dans le JSX et les utiliser dans l'effet générera toujours un tableau de dépendances différent, car chaque rendu crée une nouvelle référence. Pour éviter cela, vous pouvez déplacer la création de ces objets dans l'effet lui-même ou, en dernier recours, les stabiliser avec useMemo / useCallback.
Il est également fréquent d'être surpris de constater que la fonction de nettoyage s'exécute même lorsque le composant est encore affiché à l'écran.C’est normal : React supprime l’effet précédent avant d’appliquer le nouveau à chaque modification des dépendances. En développement, avec le mode strict, il effectue également une configuration et un nettoyage supplémentaires juste après le montage.
Enfin, si votre effet est visuel et que vous remarquez un scintillement avant son applicationVous devrez peut-être passer à useLayoutEffect Pour forcer l'exécution du rendu avant le rendu par le navigateur. Cet outil est à utiliser avec parcimonie, uniquement lorsqu'il est absolument nécessaire de bloquer le rendu jusqu'à la fin des mesures ou du positionnement.
useEffect et rendu côté serveur (SSR)
Un détail important concernant les applications de rendu côté serveur est que les effets ne s'exécutent que sur le client.Lors du rendu côté serveur (SSR), React génère le code HTML initial, mais n'exécute pas les effets. Ces derniers sont déclenchés ultérieurement, lorsque l'application est initialisée dans le navigateur.
Cela signifie que toute logique au sein de useEffect qui repose sur les API du navigateur (telles que localStorage o window) est sécurisé contre le serveurCar il ne s'exécutera pas directement côté serveur. Il est essentiel de s'assurer que le premier rendu (celui effectué sur le serveur puis répété côté client) est déterministe et ne lit aucune donnée existant uniquement dans le navigateur.
Si vous souhaitez afficher un contenu différent sur le serveur et le client, une pratique courante consiste à utiliser un état comme didMountAu départ, il est dans false, et dans un useEffect avec [] tu le mets sur trueTant que cette condition est fausse, vous affichez une version « sûre » du composant ; lorsqu'elle devient vraie, vous pouvez alors le lire. localStorage, modifier le DOM, etc. Cependant, essayez de veiller à ce que le changement visuel ne soit pas trop brutal pour les utilisateurs disposant d'une connexion lente.
En général, plus votre arbre de composants est indépendant de l'environnement, moins vous aurez de surprises en combinant le rendu côté serveur (SSR) avec les hooks.Réservez useEffect à l'intégration réelle avec des systèmes externes, car c'est à cela qu'il est destiné.
La maîtrise de useState et useEffect implique de comprendre que les composants sont « recréés » à chaque rendu, que les effets appartiennent à un cycle de vie spécifique et que le tableau de dépendances décrit la relation entre votre code et les données réactives.Lorsque vous aurez intégré ce modèle mental, la sensation de magie noire disparaîtra et vous commencerez à utiliser ces Hooks avec aisance, en écrivant des composants plus déclaratifs, plus propres et plus faciles à maintenir, même dans de grandes applications React.
Écrivain passionné par le monde des octets et de la technologie en général. J'aime partager mes connaissances à travers l'écriture, et c'est ce que je vais faire dans ce blog, vous montrer toutes les choses les plus intéressantes sur les gadgets, les logiciels, le matériel, les tendances technologiques et plus encore. Mon objectif est de vous aider à naviguer dans le monde numérique de manière simple et divertissante.