React est l’une des bibliothèques JavaScript les plus populaires pour la construction d’interfaces utilisateur. Lors de la construction de ces interfaces, vous pouvez avoir besoin d’effectuer des effets de bord, tels que la récupération de données à partir d’une API, l’abonnement à des événements ou la manipulation du DOM.

C’est là que le puissant hook useEffect entre en jeu. Il vous permet de gérer ces effets secondaires de manière transparente, déclarative et efficace, en veillant à ce que votre interface utilisateur reste responsive et à jour.

Que vous soyez un nouveau venu dans React ou un développeur expérimenté, il est essentiel de comprendre et de maîtriser useEffect pour créer des applications robustes et dynamiques. Dans cet article, vous apprendrez comment fonctionne le hook useEffect et comment l’utiliser dans votre projet React.

Qu’est-ce que l’effet de bord dans React ?

Lorsque vous travaillez avec des composants React, il arrive que vous ayez besoin d’interagir avec des entités ou d’effectuer des actions en dehors de la portée de React. Ces interactions externes sont connues sous le nom d’effets de bord.

Dans React, la plupart des composants sont des fonctions pures, ce qui signifie qu’ils reçoivent des entrées (props) et produisent des sorties prévisibles (JSX), comme le montre l’exemple ci-dessous :

export default function App() {
  return <User userName="JaneDoe" />   
}
  
function User(props) {
  return <h1>{props.userName}</h1>; // John Doe
}

Cependant, les effets secondaires ne sont pas prévisibles car ils impliquent des interactions en dehors du champ d’application habituel de React.

Prenons un exemple où vous souhaitez modifier dynamiquement le titre de l’onglet du navigateur pour afficher l’adresse userName de l’utilisateur. Bien qu’il puisse être tentant de le faire directement dans le composant, ce n’est pas l’approche recommandée car cela est considéré comme un effet de bord :

const User = ({ userName }) => {
  document.title = `Hello ${userName}`; // ❌Never do this in the component body — It is a side effect.

  return <h1>{userName}</h1>;
}

L’exécution d’effets de bord directement dans le corps du composant peut interférer avec le processus de rendu de notre composant React.

Pour éviter toute interférence, vous devez séparer les effets secondaires de manière à ce qu’ils ne rendent ou ne fonctionnent qu’après le rendu de notre composant, ce qui garantit une séparation claire entre le processus de rendu et toutes les interactions externes nécessaires. Cette séparation est réalisée à l’aide du hook useEffect.

Comprendre les principes de base de useEffect

Le hook useEffect est conçu pour imiter les méthodes de cycle de vie telles que componentDidMount, componentDidUpdate et componentWillUnmount que l’on trouve dans les composants de classe.

Pour utiliser useEffect, vous devez l’importer depuis « react » et l’appeler dans un composant de fonction (au niveau supérieur du composant). Elle prend deux arguments : une fonction de rappel et un tableau de dépendances facultatif.

useEffect(callbackFn, [dependencies]);

Cela peut être mieux écrit comme suit :

useEffect(() => {
  // code to run when the effect is triggered
}, [dependencies]);
  • La fonction de rappel contient le code à exécuter lorsque le composant est rendu ou que la valeur de la dépendance change. C’est ici que vous effectuez les effets de bord.
  • Le tableau de dépendances spécifie les valeurs qui doivent être surveillées pour les changements. La fonction de rappel sera exécutée lorsque l’une des valeurs de ce tableau changera.

Par exemple, vous pouvez maintenant corriger l’exemple précédent pour effectuer l’effet de bord correctement dans un hook useEffect :

import { useEffect } from 'react';

const User = ({ userName }) => {
  useEffect(() => {
    document.title = `Hello ${userName}`;
  }, [userName]);
    
  return <h1>{userName}</h1>;   
}

Dans l’exemple ci-dessus, le hook useEffect sera appelé après le rendu du composant et chaque fois que la dépendance – la valeur de userName– changera.

Utilisation des dépendances dans useEffect

Les dépendances jouent un rôle crucial dans le contrôle de l’exécution de useEffect. C’est le deuxième argument du hook useEffect.

useEffect(() => {
  // code to run when the effect is triggered
}, [dependencies]);

L’utilisation d’un tableau de dépendances vide [] garantit que l’effet ne s’exécute qu’une seule fois, simulant ainsi componentDidMount. La spécification correcte des dépendances permet à l’effet de se mettre à jour lorsque des valeurs spécifiques changent, comme dans le cas de componentDidUpdate.

Remarque : vous devez faire preuve de prudence lorsque vous traitez des dépendances complexes. Les mises à jour inutiles peuvent être évitées en sélectionnant soigneusement les valeurs à inclure dans le tableau de dépendances.

Si vous omettez complètement le tableau de dépendances, l’effet sera exécuté à chaque fois que le composant sera rendu, ce qui peut entraîner des problèmes de performances.

useEffect(() => {
  // code to run when the effect is triggered
});

Dans React, comprendre le fonctionnement du rendu est un atout considérable car vous serez en mesure de connaître l’importance du tableau de dépendances.

Comment fonctionne le rendu dans React ?

Dans React, le rendu génère l’interface utilisateur (UI) en fonction de l’état actuel d’un composant et de ses accessoires. Il existe différents scénarios dans lesquels le rendu se produit. Le rendu initial se produit lorsqu’un composant est rendu ou monté pour la première fois.

Par ailleurs, un changement dans state ou props d’un composant déclenche un nouveau rendu pour s’assurer que l’interface utilisateur reflète les valeurs mises à jour. Les applications React sont construites avec une structure arborescente de composants, formant une hiérarchie. React part du composant racine lors du rendu et effectue un rendu récursif de ses composants enfants.

Cela signifie que tous les composants seront rendus si un changement se produit dans le composant racine. Il est important de noter qu’appeler des effets de bord (qui sont la plupart du temps des fonctions coûteuses) à chaque rendu peut être coûteux. Pour optimiser les performances, vous pouvez utiliser le tableau de dépendances dans le hook useEffect pour spécifier quand il doit être déclenché, limitant ainsi les re-rendus inutiles.

Utilisation avancée de useEffect : Nettoyage des effets de bord

Le hook useEffect nous permet d’effectuer des effets de bord et fournit un mécanisme pour nettoyer ces effets de bord. Cela permet de s’assurer que les ressources ou les abonnements créés pendant l’effet de bord sont correctement libérés et d’éviter les fuites de mémoire.

Voyons comment vous pouvez nettoyer les effets de bord à l’aide du hook useEffect:

useEffect(() => {
  // Perform some side effect

  // Cleanup side effect
  return () => {
    // Cleanup tasks
  };
}, []);

Dans l’extrait de code ci-dessus, la fonction de nettoyage est définie comme une valeur de retour dans le hook useEffect. Cette fonction est invoquée lorsque le composant est sur le point d’être démonté ou avant un nouveau rendu. Elle vous permet de nettoyer les ressources ou les abonnements établis pendant l’effet de bord.

Voici quelques exemples d’utilisation avancée du hook useEffect pour le nettoyage des effets de bord :

1. Nettoyage des intervalles

useEffect(() => {
    const interval = setInterval(() => {
        // Perform some repeated action
    }, 1000);
    return () => {
        clearInterval(interval); // Clean up the interval
    };
}, []);

Dans cet exemple, nous avons mis en place un intervalle qui effectue une action toutes les secondes. La fonction de nettoyage efface l’intervalle pour éviter qu’il ne s’exécute après le démontage du composant.

2. Nettoyage des auditeurs d’événements

useEffect(() => {
    const handleClick = () => {
        // Handle the click event
    };

    window.addEventListener('click', handleClick);

    return () => {
        window.removeEventListener('click', handleClick); // Clean up the event listener
    };
}, []);

Ici, nous créons un écouteur d’évènement pour l’évènement click sur l’objet window. La fonction de nettoyage supprime l’écouteur d’évènement pour éviter les fuites de mémoire et garantir un nettoyage correct.

N’oubliez pas que la fonction de nettoyage est facultative, mais qu’il est fortement recommandé de nettoyer toutes les ressources ou tous les abonnements afin de maintenir une application saine et efficace.

Utilisation du hook useEffect

Le hook useEffect vous permet d’effectuer des tâches qui impliquent une interaction avec des entités ou des API externes, telles que des API web comme localStorage ou des sources de données externes.

Explorons l’utilisation du hook useEffect dans différents scénarios :

1. Travailler avec des API web (localStorage)

useEffect(() => {
 // Storing data in localStorage
  localStorage.setItem('key', 'value');
  // Retrieving data from localStorage
  const data = localStorage.getItem('key');
  // Cleanup: Clearing localStorage when component unmount
  return () => {
    localStorage.removeItem('key');
  };
}, []);

Dans cet exemple, le hook useEffect est utilisé pour stocker et récupérer des données dans le localStorage du navigateur. La fonction de nettoyage garantit que le localStorage est effacé lorsque le composant est démonté (ce n’est pas toujours un bon cas d’utilisation, car vous pouvez vouloir conserver les données du localStorage jusqu’à ce que le navigateur soit actualisé).

2. Récupération de données à partir d’une API externe

useEffect(() => {
  // Fetching data from an external API
  fetch('https://api.example.com/data')
    .then((response) => response.json())
    .then((data) => {
      // Do something with the data
    });
}, []);

Ici, le hook useEffect est utilisé pour récupérer des données d’une API externe. Les données récupérées peuvent ensuite être traitées et utilisées dans le composant. Il n’est pas obligatoire d’ajouter systématiquement une fonction de nettoyage.

Autres effets de bord populaires

Le hook useEffect peut être utilisé pour divers autres effets secondaires, tels que :

A. S’abonner à des événements :

useEffect(() => {
  window.addEventListener('scroll', handleScroll);
  return () => {
    window.removeEventListener('scroll', handleScroll);
  };
}, []);

B. Modifier le titre du document :

useEffect(() => {
  document.title = 'New Title';
  return () => {
    document.title = 'Previous Title';
  };
}, []);

C. Gestion des minuteries :

useEffect(() => {
  const timer = setInterval(() => {
    // Do something repeatedly
  }, 1000);
  return () => {
    clearInterval(timer);
  };
}, []);

Erreurs courantes d’useEffect et comment les éviter

Lorsque vous travaillez avec le hook useEffect dans React, il est possible de rencontrer des erreurs qui peuvent conduire à un comportement inattendu ou à des problèmes de performance.

Comprendre ces erreurs et savoir comment les éviter peut aider à garantir une utilisation fluide et sans erreur de useEffect.

Examinons quelques erreurs courantes de useEffect et leurs solutions :

1. Tableau de dépendance manquant

Une erreur fréquente est d’oublier d’inclure un tableau de dépendances comme deuxième argument du crochet useEffect.

ESLint signalera toujours cette erreur comme un avertissement car elle peut entraîner des comportements non souhaités, tels qu’un re-rendu excessif ou des données périmées.

useEffect(() => {
  // Side effect code
}); // Missing dependency array

Solution : Fournissez toujours un tableau de dépendances à useEffect, même s’il est vide. Incluez toutes les variables ou valeurs dont l’effet dépend. Cela aide React à déterminer quand l’effet doit être exécuté ou ignoré.

useEffect(() => {
  // Side effect code
}, []); // Empty dependency array or with appropriate dependencies

2. Tableau de dépendances incorrect

Fournir un tableau de dépendances incorrect peut également entraîner des problèmes. Si le tableau de dépendances n’est pas défini avec précision, l’effet peut ne pas s’exécuter lorsque les dépendances prévues changent.

const count = 5;
const counter = 0;
useEffect(() => {
  // Side effect code that depends on 'count'
  let answer = count + 15;
}, [count]); // Incorrect dependency array

Solution : Veillez à inclure toutes les dépendances nécessaires dans le tableau de dépendances. Si l’effet dépend de plusieurs variables, incluez-les toutes afin de déclencher l’effet lorsque l’une des dépendances change.

const count = 5;
useEffect(() => {
  // Side effect code that depends on 'count'
  let answer = count + 15;
}, [count]); // Correct dependency array

3. Boucles infinies

La création d’une boucle infinie peut se produire lorsque l’effet modifie un état ou un élément qui dépend également de l’effet lui-même. L’effet est alors déclenché de manière répétée, ce qui entraîne un re-rendu excessif et risque de bloquer l’application.

const [count, setCount] = useState(0);
useEffect(() => {
  setCount(count + 1); // Modifying the dependency 'count' inside the effect
}, [count]); // Dependency array includes 'count'

Solution : Assurez-vous que l’effet ne modifie pas directement une dépendance incluse dans son tableau de dépendances. Créez plutôt des variables distinctes ou utilisez d’autres techniques de gestion d’état pour gérer les changements nécessaires.

const [count, setCount] = useState(0);
useEffect(() => {
  setCount((prevCount) => prevCount + 1); // Modifying the 'count' using a callback
}, []); // You can safely remove the 'count' dependency

4. Oubli de nettoyage

Négliger le nettoyage des effets secondaires peut entraîner des fuites de mémoire ou une consommation inutile de ressources. Ne pas nettoyer les auditeurs d’évènements, les intervalles ou les abonnements peut entraîner un comportement inattendu, notamment lorsque le composant est démonté.

useEffect(() => {
  const timer = setInterval(() => {
    // Perform some action repeatedly
  }, 1000);
  // Missing cleanup
  return () => {
    clearInterval(timer); // Cleanup missing in the return statement
  };
}, []);

Solution : Fournissez toujours une fonction de nettoyage dans l’instruction de retour du hook useEffect.

useEffect(() => {
  const timer = setInterval(() => {
    // Perform some action repeatedly
  }, 1000);
  return () => {
    clearInterval(timer); // Cleanup included in the return statement
  };
}, []);

En étant conscient de ces erreurs courantes de useEffect et en suivant les solutions recommandées, vous pouvez éviter les pièges potentiels et garantir l’utilisation correcte et efficace du hook useEffect dans vos applications React.

Résumé

Le hook useEffect de React est un outil puissant pour gérer les effets de bord dans les composants de fonction. Maintenant que vous avez une meilleure compréhension de useEffect, il est temps d’appliquer vos connaissances et de donner vie à vos applications React.

Vous pouvez également faire tourner votre application React en production en la déployant sur l’hébergement d’applications de Kinsta gratuitement !

À vous de jouer. Que pensez-vous du hook useEffect ? N’hésitez pas à le partager avec nous dans la section des commentaires ci-dessous.