Introduction
En explorant React, j’ai souvent utilisé useEffect sans trop y réfléchir. Lors d’une formation, j’ai découvert que certaines de mes habitudes n’étaient pas optimales et pouvaient même poser problème.
Dans cet article, je partage avec vous l’essentiel sur useEffect : comment l’utiliser correctement, éviter les erreurs courantes et adopter les meilleures pratiques.
UseEffect c’est quoi ?
useEffect est un hook puissant dans React, conçu pour gérer les effets secondaires dans les composants fonctionnels. Il remplace les méthodes de cycle de vie telles que componentDidMount, componentDidUpdate, et componentWillUnmount.
Syntaxe et Utilisation
La syntaxe de base de useEffect est la suivante :
useEffect(() => {
// code à exécuter lorsque l'effet est déclenché
}, [dependances]);
Il prend deux arguments : une fonction callback et un tableau de dépendances optionnel. La fonction de rappel contient le code à exécuter, tandis que le tableau de dépendances spécifie les valeurs à surveiller pour les changements.
Les dépendances jouent un rôle essentiel dans le contrôle de l’exécution de useEffect.
useEffect(() => {
}, []);
L’utilisation d’un useEffect avec un tableau vide comme dépendances, fait que l’effet sera lancé une seule fois, lors du premier rendu du composant, un peu comme avec componentDidMount
useEffect(() => {
// code à exécuter lorsque l'effet est déclenché
});
Si l’on omet le tableau de dépendances, l’effet sera exécuté à chaque rendu, ce qui peut nuire aux performances.
useEffect(() => {
}, [valeur]);
Ici, l’effet sera exécuté chaque fois que la valeur spécifiée change simulant componentDidUpdate.
Nettoyage des Effets Secondaires
Un autre aspect important de useEffect est le nettoyage des effets secondaires. Cela permet d’éviter des fuites de mémoire, notamment lorsque le composant est démonté ou que l’effet doit être réexécuté.
useEffect(() => {
const interval = setInterval(() => {
// Perform some repeated action
}, 1000);
return () => {
clearInterval(interval); // Clean up the interval
};
}, []);
Erreurs Courantes et Meilleures Pratiques avec useEffect
L’utilisation de useEffect peut rapidement devenir source d’erreurs si certaines précautions ne sont pas prises. Voici les erreurs les plus fréquentes et comment les éviter en appliquant les bonnes pratiques.
1. Oublier le tableau de dépendances
Erreur :
useEffect(() => {
fetchData();
});
Problème : L’effet s’exécute à chaque rendu, entraînant des requêtes répétées et une surcharge inutile.
Bonne pratique : Toujours spécifier un tableau de dépendances, même s’il est vide ([]).
2. Mauvaise gestion des dépendances
Erreur :
useEffect(() => {
console.log(count);
}, []);
Problème : L’effet ne se déclenche pas lorsque count change, car il n’est pas inclus dans les dépendances.
Bonne pratique : Inclure toutes les variables utilisées dans le useEffect dans le tableau de dépendances.
3. Créer une boucle infinie
Erreur :
useEffect(() => {
setState(state + 1);
}, [state]);
Problème : La modification de state entraîne un nouveau rendu, ce qui relance l’effet en boucle infinie.
Bonne pratique : Utiliser une mise à jour basée sur l’état précédent pour éviter un déclenchement infini.
useEffect(() => {
setState(prevState => prevState + 1);
}, []);
4. Oublier le nettoyage d’un effet
Erreur :
useEffect(() => {
window.addEventListener("resize", handleResize);
}, []);
Problème : L’écouteur d’événement continue d’exister même après le démontage du composant, ce qui entraîne des fuites de mémoire.
Bonne pratique : Toujours retourner une fonction de nettoyage (cleanup function). Cette approche est particulièrement utile pour les abonnements (WebSocket, setInterval, etc.).
useEffect(() => {
const handleResize = () => console.log("Fenêtre redimensionnée !");
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
5. Ne pas abuser de useEffect
Mauvaise habitude : Utiliser useEffect pour tout, même quand ce n’est pas nécessaire.
Parfois, un effet peut être remplacé par :
useMemopour mémoriser le résultat d’un calcul coûteux ou dépendant de certaines données.useCallbackpour mémoriser des fonctions.- Lever l’effet en dehors du composant si possible (ex. : via un contexte global).
- useReducer pour gérer un état complexe ou conditionnel à partir de plusieurs actions. Contrairement à useState, il centralise la logique de mise à jour, ce qui évite d’avoir plusieurs useEffect en cascade pour synchroniser les états.
Exemple :
Mauvais usage de useEffect pour dériver un état :
useEffect(() => {
setFilteredList(list.filter(item => item.active));
}, [list]);
Meilleure alternative avec useMemo :
useMemo permet de recalculer filteredList uniquement quand list change, sans effet secondaire :
const filteredList = useMemo(() => list.filter(item => item.active), [list]);
C’est plus simple, plus lisible, sans gestion manuelle de setState ni dépendance au cycle de vie du composant.
un autre exemple d’utilisation d’useMemo :
function UserList({ users }) {
const activeUsers = useMemo(() => {
return users.filter(user => user.isActive);
}, [users]);
return (
<ul>
{activeUsers.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Ici, le tableau users peut être long ou mis à jour fréquemment. Grâce à useMemo, on évite de recalculer activeUsers à chaque rendu si users n’a pas changé.
Conclusion
useEffect est un outil puissant mais qui peut vite causer des soucis s’il est mal utilisé. En gérant bien les dépendances, en évitant les re-rendus inutiles et en nettoyant correctement ses effets, on améliore la performance et la stabilité des composants.