OUJOOD.COM
Introduction
Le Hook `useEffect` est utilisé pour exécuter des effets secondaires dans vos composants fonctionnels React. Ces effets peuvent inclure des appels API, la mise à jour du DOM, ou l'abonnement à des événements externes. Avant les Hooks, ces fonctionnalités étaient gérées via des méthodes de cycle de vie dans les composants basés sur des classes.
Dans ce chapitre, nous allons explorer :
- Qu'est-ce qu'un effet secondaire en React ?
- Comment utiliser `useEffect` pour exécuter du code après le rendu.
- Des exemples pratiques pour illustrer son fonctionnement.
1. Qu'est-ce qu'un Effet Secondaire en React ?
Un effet secondaire (ou "side effect") est une action qui se produit en dehors du flux principal de données React. Cela peut inclure :
- Appels API : Récupération de données depuis un serveur externe.
- Mise à jour du DOM : Modification directe des éléments HTML après le rendu.
- Souscription à des événements : Écoute d'événements comme les changements de fenêtre ou les mises à jour de l'état global.
Le Hook `useEffect` permet d'exécuter ces effets de manière contrôlée et efficace.
2. Utilisation de Base de `useEffect`
Voici un exemple simple où nous utilisons `useEffect` pour afficher un message dans la console après que le composant a été rendu :
import React, { useState, useEffect } from 'react'; import { createRoot } from 'react-dom/client'; function Composant() { useEffect(() => { console.log('Le composant a été rendu.'); }, []); // Le tableau vide [] signifie que l'effet ne doit être exécuté qu'une seule fois après le rendu initial return <h1>Bienvenue dans notre application React !</h1>; } const root = createRoot(document.getElementById('root')); root.render(<Composant />);
Explication détaillée ligne par ligne :
-
import React, { useState, useEffect } from 'react';
:- Nous importons React ainsi que les Hooks `useState` et `useEffect` depuis la bibliothèque React.
- `useEffect` est utilisé pour exécuter des effets secondaires dans un composant fonctionnel.
-
useEffect(() => { ... }, []);
:- Cette ligne définit un effet secondaire qui sera exécuté après le rendu initial du composant.
- Le tableau vide `[]` en deuxième argument indique que cet effet ne doit être exécuté qu'une seule fois après le premier rendu.
-
console.log('Le composant a été rendu.');
:- Affiche un message dans la console lorsque l'effet est exécuté.
-
const root = createRoot(document.getElementById('root'));
:- Cette ligne crée une racine React pour insérer notre composant dans le DOM.
-
root.render(<Composant />);
:- Rend le composant `Composant` dans l'élément HTML ayant l'id `root`.
3. Exécution d'un Effet Après un Changement Spécifique
Vous pouvez également configurer `useEffect` pour exécuter un effet chaque fois qu'une certaine variable d'état ou prop change. Voici un exemple où nous mettons à jour le titre de la page lorsque l'utilisateur modifie un compteur :
import React, { useState, useEffect } from 'react'; import { createRoot } from 'react-dom/client'; function Compteur() { const [compte, setCompte] = useState(0); useEffect(() => { document.title = `Vous avez cliqué ${compte} fois.`; // Met à jour le titre de la page }, [compte]); // L'effet est exécuté chaque fois que "compte" change function incrementer() { setCompte(compte + 1); } return ( <div> <p>Vous avez cliqué {compte} fois.</p> <button onClick={incrementer}>Incrémenter</button> </div> ); } const root = createRoot(document.getElementById('root')); root.render(<Compteur />);
Explication détaillée ligne par ligne :
-
useEffect(() => { ... }, [compte]);
:- Cet effet est configuré pour s'exécuter chaque fois que la variable d'état `compte` change.
- Le tableau `[compte]` en deuxième argument liste les dépendances de l'effet. Ici, `compte` est la seule dépendance.
-
document.title = `Vous avez cliqué ${compte} fois.`;
:- Cette ligne met à jour dynamiquement le titre de la page avec la valeur actuelle de `compte`.
-
function incrementer() { ... }
:- Cette fonction incrémente la valeur de `compte` de 1 lorsqu'elle est appelée.
-
<button onClick={incrementer}>Incrémenter</button>
:- Lorsque le bouton est cliqué, la fonction `incrementer` est exécutée, mettant à jour l'état `compte`.
- Cela déclenche également l'effet défini dans `useEffect`, car `compte` est une dépendance.
4. Nettoyage d'un Effet avec `useEffect`
Lorsque vous utilisez des effets secondaires comme des intervalles temporels ou des abonnements à des événements externes, il est crucial de nettoyer ces effets lorsque le composant est démonté. Cela évite les fuites mémoire et garantit un comportement correct de votre application.
import React, { useState, useEffect } from 'react'; import { createRoot } from 'react-dom/client'; function Horloge() { const [heure, setHeure] = useState(new Date().toLocaleTimeString()); useEffect(() => { const timerID = setInterval(() => { setHeure(new Date().toLocaleTimeString()); // Met à jour l'heure toutes les secondes }, 1000); // Fonction de nettoyage pour arrêter l'intervalle lorsque le composant est démonté return () => clearInterval(timerID); }, []); // L'effet est exécuté une seule fois au montage return ( <div> <h1>Heure actuelle :</h1> <h2>{heure}</h2> </div> ); } const root = createRoot(document.getElementById('root')); root.render(<Horloge />);
Explication détaillée ligne par ligne :
-
import React, { useState, useEffect } from 'react';
:- Nous importons React ainsi que les Hooks
useState
etuseEffect
. useState
permet de gérer l'état local (ici, l'heure).useEffect
permet d'exécuter des effets secondaires après le rendu initial ou lors de changements spécifiques.
- Nous importons React ainsi que les Hooks
-
import { createRoot } from 'react-dom/client';
:- Cette ligne importe la méthode
createRoot
depuisreact-dom/client
, recommandée pour React 18 et versions ultérieures. createRoot
remplaceReactDOM.render()
pour un rendu plus moderne et aligné avec les futures évolutions de React.
- Cette ligne importe la méthode
-
const [heure, setHeure] = useState(new Date().toLocaleTimeString());
:- Cette ligne initialise une variable d'état appelée
heure
avec la valeur initiale étant l'heure actuelle formatée (new Date().toLocaleTimeString()
). setHeure
est une fonction utilisée pour mettre à jour cette variable d'état.
- Cette ligne initialise une variable d'état appelée
-
useEffect(() => { ... }, []);
:- Cette ligne définit un effet secondaire qui sera exécuté une seule fois après le rendu initial du composant.
- Le tableau vide
[]
en deuxième argument signifie que cet effet ne dépend d'aucune variable d'état ou prop, donc il s'exécute uniquement au montage du composant.
-
const timerID = setInterval(() => { ... }, 1000);
:- Cette ligne crée un intervalle temporel qui met à jour l'état
heure
toutes les secondes. setInterval
est une fonction JavaScript native qui exécute une fonction donnée à intervalles réguliers (en millisecondes). Ici, elle appellesetHeure
toutes les 1000 ms (1 seconde).
- Cette ligne crée un intervalle temporel qui met à jour l'état
-
return () => clearInterval(timerID);
:- Ceci est la **fonction de nettoyage** retournée par
useEffect
. - Lorsque le composant est démonté (par exemple, s'il est supprimé du DOM), cette fonction est automatiquement appelée pour arrêter l'intervalle temporel.
- Cela empêche les fuites mémoire et garantit que l'intervalle ne continue pas à tourner indéfiniment.
- Ceci est la **fonction de nettoyage** retournée par
-
<h1>Heure actuelle :</h1>
:- Cet élément affiche un titre statique indiquant "Heure actuelle".
-
<h2>{heure}</h2>
:- Cet élément affiche dynamiquement la valeur de l'état
heure
, qui est mise à jour toutes les secondes grâce àuseEffect
.
- Cet élément affiche dynamiquement la valeur de l'état
-
const root = createRoot(document.getElementById('root'));
:- Cette ligne crée une instance de racine React appelée
root
. document.getElementById('root')
spécifie l'élément HTML où le composant sera inséré.
- Cette ligne crée une instance de racine React appelée
-
root.render(<Horloge />);
:- Cette ligne rend le composant
Horloge
dans l'élément HTML ayant l'idroot
. - Grâce à
createRoot
, cette méthode est alignée avec les meilleures pratiques React 18.
- Cette ligne rend le composant
Pourquoi Ajouter une Fonction de Nettoyage ?
Dans cet exemple, nous utilisons setInterval
pour créer un intervalle temporel qui met à jour l'état toutes les secondes. Cependant, si nous ne nettoyons pas cet intervalle lorsque le composant est démonté, cela pourrait entraîner des problèmes comme :
- Fuites mémoire : L'intervalle continuerait à tourner même si le composant n'est plus utilisé, consommant inutilement des ressources système.
- Comportements inattendus : Si plusieurs instances du composant sont montées/démontées rapidement, cela pourrait provoquer des conflits entre différents intervalles.
La fonction de nettoyage (clearInterval(timerID)
) garantit que l'intervalle est correctement arrêté lorsque le composant est démonté.
Amélioration avec React 18 : Utilisation de `createRoot`
Dans les versions antérieures de React, nous utilisions souvent ReactDOM.render()
pour rendre nos composants. Avec React 18, createRoot
est maintenant la méthode recommandée car elle offre des performances optimisées et est alignée avec le concurrent rendering.
- Concurrent Rendering : Permet à React de mieux gérer les mises à jour asynchrones pour un rendu plus fluide.
- Compatibilité Future : Utiliser
createRoot
garantit que votre code reste compatible avec les futures versions de React.
5. Meilleures Pratiques pour `useEffect`
Pour utiliser `useEffect` efficacement, voici quelques conseils :
- Définissez explicitement les dépendances : Ajoutez toutes les variables dont votre effet dépend dans le tableau de dépendances pour éviter des comportements inattendus.
- Incluez toujours une fonction de nettoyage si nécessaire : Par exemple, arrêtez les intervalles ou les abonnements pour éviter des fuites mémoire.
- Évitez les effets coûteux dans le tableau de dépendances vide : Si votre effet est trop coûteux, limitez son exécution aux moments nécessaires.
Version Optimisée et Améliorée de l'Horloge
Dans cette section, nous allons explorer une version optimisée et améliorée du composant Horloge que nous avons vu précédemment. Cette version incorpore plusieurs améliorations, notamment :
- Utilisation d'un objet Date complet : L'état `heure` est maintenant initialisé avec un objet `Date`, ce qui permet d'accéder à plus de fonctionnalités.
- Ajout de styles inline personnalisés : Une approche de stylisation avancée est utilisée pour rendre l'interface utilisateur plus attrayante.
- Compatibilité avec React 18 : Utilisation de `createRoot` pour garantir des performances optimales et une compatibilité future.
import React, { useState, useEffect } from 'react'; import { createRoot } from 'react-dom/client'; function Horloge() { const [heure, setHeure] = useState(new Date()); // Initialisation avec un objet Date useEffect(() => { const timerID = setInterval(() => { setHeure(new Date()); // Met à jour l'état avec un nouvel objet Date toutes les secondes }, 1000); return () => clearInterval(timerID); // Nettoyage de l'intervalle au démontage }, []); // Exécution unique au montage const styles = { container: { textAlign: "center", marginTop: "20px", fontFamily: "Arial, sans-serif" }, // Style pour le conteneur principal time: { fontSize: "2rem", fontWeight: "bold", color: "#007BFF" } // Style pour afficher l'heure }; return ( <div style={styles.container}> <h1>Heure actuelle :</h1> <h2 style={styles.time}>{heure.toLocaleTimeString()}</h2> {/* Affichage dynamique de l'heure */} </div> ); } const root = createRoot(document.getElementById('root')); // Création de la racine React avec createRoot (React 18+) root.render(<Horloge />); // Rendu du composant Horloge dans le DOM
Explication détaillée ligne par ligne :
-
import React, { useState, useEffect } from 'react';
:- Nous importons React ainsi que les Hooks
useState
etuseEffect
. useState
est utilisé pour gérer l'état local (ici, l'heure).useEffect
exécute des effets secondaires après le rendu ou lors de changements spécifiques.
- Nous importons React ainsi que les Hooks
-
import { createRoot } from 'react-dom/client';
:- Cette ligne importe la méthode
createRoot
depuisreact-dom/client
, recommandée pour React 18 et versions ultérieures. createRoot
remplaceReactDOM.render()
pour un rendu plus moderne et aligné avec les futures évolutions de React.
- Cette ligne importe la méthode
-
const [heure, setHeure] = useState(new Date());
:- Ici, l'état `heure` est initialisé avec un objet `Date` représentant l'heure actuelle.
- Contrairement à la version précédente où seule la chaîne de caractères formatée était stockée, cette version conserve l'objet `Date` entier, offrant davantage de flexibilité pour manipuler d'autres propriétés (ex. date, minute, seconde).
-
useEffect(() => { ... }, []);
:- Cet effet est configuré pour s'exécuter une seule fois après le rendu initial du composant.
- Le tableau vide `[]` en deuxième argument signifie qu'il n'y a aucune dépendance, donc cet effet ne sera pas recalculé lors de changements d'état ou de props.
-
const timerID = setInterval(() => { ... }, 1000);
:- Cette ligne crée un intervalle temporel qui met à jour l'état `heure` toutes les secondes.
setHeure(new Date())
: L'état `heure` est mis à jour avec un nouvel objet `Date` représentant l'heure actuelle.
-
return () => clearInterval(timerID);
:- Ceci est la fonction de nettoyage retournée par
useEffect
. - Lorsque le composant est démonté (par exemple, s'il est supprimé du DOM), cette fonction arrête automatiquement l'intervalle créé avec
setInterval
. - Cela empêche les fuites mémoire et garantit que l'intervalle ne continue pas à tourner indéfiniment.
- Ceci est la fonction de nettoyage retournée par
-
const styles = { ... }
:- Cette variable définit des styles CSS sous forme d'objets JavaScript pour personnaliser l'apparence du composant.
container
: Centre le texte horizontalement (textAlign: "center"
), ajoute un espace au-dessus du composant (marginTop: "20px"
) et utilise une police standard (fontFamily: "Arial, sans-serif"
).time
: Définit une taille de police importante (fontSize: "2rem"
), applique un poids gras (fontWeight: "bold"
) et utilise une couleur bleue (color: "#007BFF"
) pour rendre l'affichage de l'heure plus visible.
-
<div style={styles.container}>
:- Ce fragment applique les styles définis dans
styles.container
au conteneur principal. - Les styles inline sont une alternative simple pour appliquer des styles locaux sans avoir besoin de fichiers CSS externes.
- Ce fragment applique les styles définis dans
-
<h2 style={styles.time}>{heure.toLocaleTimeString()}</h2>
:- Cet élément affiche l'heure formatée grâce à la méthode
toLocaleTimeString()
. - Les styles définis dans
styles.time
sont appliqués pour rendre l'affichage de l'heure plus attractif.
- Cet élément affiche l'heure formatée grâce à la méthode
-
const root = createRoot(document.getElementById('root'));
:- Cette ligne crée une instance de racine React appelée
root
. document.getElementById('root')
spécifie l'élément HTML où le composant sera inséré.
- Cette ligne crée une instance de racine React appelée
-
root.render(<Horloge />);
:- Rend le composant
Horloge
dans l'élément HTML ayant l'idroot
. - Cette méthode est alignée avec les meilleures pratiques React 18, garantissant des performances optimisées.
- Rend le composant
Pourquoi Stocker un Objet Date Complet ?
Contrairement à la version précédente où seule la chaîne de caractères formatée était stockée dans l'état, cette version conserve un objet Date
complet. Voici pourquoi cela est avantageux :
- Flexibilité accrue : Vous pouvez accéder à d'autres propriétés de l'objet
Date
, telles que la date, les minutes ou les secondes, si nécessaire. - Moins de calculs redondants : En stockant directement l'objet
Date
, vous évitez de convertir l'heure en chaîne de caractères à chaque re-render.
Amélioration avec les Styles Inline
Les styles inline permettent de personnaliser rapidement l'apparence d'un composant sans avoir besoin de fichiers CSS externes. Voici comment ils sont utilisés dans cet exemple :
- Centre le Texte : La propriété
textAlign: "center"
aligne le texte au centre du conteneur. - Taille de Police Dynamique : La propriété
fontSize: "2rem"
rend l'affichage de l'heure plus grand et plus visible. - Couleur Attractives : La propriété
color: "#007BFF"
applique une couleur bleue vive pour attirer l'attention sur l'heure.
Compatibilité avec React 18
Avec l'arrivée de React 18, il est recommandé d'utiliser createRoot
au lieu de ReactDOM.render()
. Voici pourquoi :
- Performances Optimisées :
createRoot
exploite le concurrent rendering pour un rendu plus fluide. - Compatibilité Future : Utiliser la méthode recommandée garantit que votre code reste compatible avec les futures versions de React.
- API Plus Moderne :
createRoot
est conçu pour être utilisé avec React 18 et offre une meilleure organisation du code.
Cette version optimisée de l'Horloge illustre plusieurs concepts avancés de React, notamment l'utilisation d'un objet Date
complet, les styles inline pour une personnalisation rapide, et la compatibilité avec React 18 via createRoot
. Ces améliorations rendent le composant plus flexible, performant et visuellement attrayant.
Conclusion
Vous avez maintenant appris à utiliser le Hook `useEffect` pour exécuter des effets secondaires dans vos composants fonctionnels React. En combinant des appels API, des mises à jour du DOM, et des fonctions de nettoyage, vous pouvez créer des applications interactives et performantes.
Prochain chapitre : useContext