OUJOOD.COM
Introduction
Le Hook `useMemo` est utilisé pour mémoriser des valeurs calculées afin d'éviter des recalculs inutiles lors des re-renders. Cela peut considérablement améliorer les performances de vos applications React, surtout lorsque ces calculs sont coûteux ou impliquent des données complexes.
Dans ce chapitre, nous allons explorer :
- Qu'est-ce que `useMemo` ?
- Comment créer et utiliser une valeur mémorisée.
- Des exemples pratiques pour illustrer son fonctionnement.
1. Qu'est-ce que `useMemo` ?
`useMemo` est un Hook React qui renvoie une valeur mémorisée. Cette valeur ne sera recalculée que si ses dépendances changent. Voici pourquoi cela est important :
- Optimisation des Performances : En mémorisant des valeurs coûteuses à calculer, vous évitez des recalculs inutiles lors des re-renders.
- Rendu Plus Efficace : Les composants enfants qui utilisent cette valeur mémorisée ne seront pas forcés de se re-renderer si la valeur reste inchangée.
Contrairement à `useState`, `useMemo` n'induit pas de re-render lorsqu'il met à jour sa valeur. Il est donc idéal pour des cas où vous voulez simplement optimiser des calculs sans affecter l'état du composant.
2. Création d'une Valeur Mémorisée avec `useMemo`
Voici un exemple simple où nous utilisons `useMemo` pour mémoriser une valeur calculée basée sur un état local :
import React, { useState, useMemo } from 'react'; import { createRoot } from 'react-dom/client'; function App() { const [compte, setCompte] = useState(0); // État principal const [nom, setNom] = useState('Alice'); // État secondaire // Valeur mémorisée avec useMemo const doubleCompte = useMemo(() => { console.log('Calcul du double du compte...'); return compte * 2; // Calcule le double de "compte" }, [compte]); // La valeur sera recalculée uniquement si "compte" change function changerNom() { setNom((prevState) => prevState === 'Alice' ? 'Bob' : 'Alice'); } return ( <div> <h1>Exemple avec useMemo</h1> <p>Compteur : {compte}</p> <p>Nom : {nom}</p> <p>Double du compteur : {doubleCompte}</p> <button onClick={() => setCompte(compte + 1)}>Incrémenter</button> <button onClick={changerNom}>Changer de nom</button> </div> ); } const root = createRoot(document.getElementById('root')); root.render(<App />);
Explication détaillée du code React avec useMemo
Notre code React utilise useMemo
pour optimiser le calcul du double de la valeur du compteur (compte
).
1. État avec useState
compte
: Stocke la valeur du compteur.nom
: Stocke un nom qui peut être changé entre "Alice" et "Bob".
2. Utilisation de useMemo
La fonction doubleCompte
est mémorisée grâce à useMemo
, ce qui signifie qu'elle ne sera recalculée que lorsque compte
change.
Si nom
est modifié, doubleCompte
ne sera pas recalculé inutilement, ce qui optimise les performances.
3. Fonctionnement des boutons
- Un bouton pour incrémenter la valeur du compteur.
- Un autre bouton pour changer de nom.
4. Comportement attendu
- Lorsque vous cliquez sur "Incrémenter",
compte
augmente de 1 etdoubleCompte
est recalculé. - Lorsque vous cliquez sur "Changer de nom", seul
nom
change, etdoubleCompte
reste inchangé.
5. Pourquoi utiliser useMemo
ici ?
Dans une petite application comme celle-ci, useMemo
n'apporte pas de grand bénéfice,
mais dans des applications plus complexes où les calculs sont lourds, useMemo
évite des recalculs inutiles et améliore les performances.
Explication détaillée ligne par ligne
1. import React, { useState, useMemo } from 'react'; 2. import { createRoot } from 'react-dom/client'; // Importation de React et des hooks nécessaires : useState pour gérer //l'état et useMemo pour optimiser le calcul du double du compteur. // createRoot est utilisé pour le rendu de l'application dans //l'élément HTML avec l'ID 'root'. 3. function App() { 4. const [compte, setCompte] = useState(0); 5. const [nom, setNom] = useState('Alice'); // Déclaration du composant fonctionnel "App". // Définition de l'état `compte` avec une valeur initiale de 0. // Définition de l'état `nom` avec une valeur initiale "Alice". 6. const doubleCompte = useMemo(() => { 7. console.log('Calcul du double du compte...'); 8. return compte * 2; 9. }, [compte]); // Utilisation de useMemo pour mémoriser la valeur de `doubleCompte`. // Cette fonction sera exécutée seulement si `compte` change. // À chaque mise à jour de `compte`, un message "Calcul du double //du compte..." est affiché dans la console. 10. function changerNom() { 11. setNom((prevState) => prevState === 'Alice' ? 'Bob' : 'Alice'); 12. } // Définition de la fonction "changerNom" qui bascule entre //"Alice" et "Bob" à chaque appel. 13. return ( 14. <div> 15. <h1>Exemple avec useMemo</h1> 16. <p>Compteur : {compte}</p> 17. <p>Nom : {nom}</p> 18. <p>Double du compteur : {doubleCompte}</p> 19. <button onClick={() => setCompte(compte + 1)} >Incrémenter</button> 20. <button onClick={changerNom}>Changer de nom</button> 21. </div> 22. ); // Retour du JSX contenant l'affichage de l'application. // Affichage du compteur, du nom et du double du compteur. // Ajout de boutons pour incrémenter le compteur et changer de nom. 23. } 24. const root = createRoot(document.getElementById('root')); 25. root.render(<App />); // Sélection de l'élément HTML avec l'ID 'root' et rendu du composant App.
6. Optimisation supplémentaire
Si vous souhaitez optimiser encore plus, vous pouvez utiliser useCallback
pour éviter la recréation de fonctions à chaque rendu.
3. Exemple Avancé : Calcul Coûteux avec `useMemo`
Imaginons que vous ayez besoin de calculer une valeur coûteuse (par exemple, un tableau de nombres filtrés). Voici comment utiliser `useMemo` pour optimiser ce calcul :
import React, { useState, useMemo } from 'react'; import { createRoot } from 'react-dom/client'; // Fonction coûteuse pour filtrer des nombres pairs function filtreNombresPairs(nombres) { console.log('Filtrage des nombres pairs...'); return nombres.filter((nombre) => nombre % 2 === 0); } function App() { const [nombres, setNombres] = useState([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); const [filtreActif, setFiltreActif] = useState(false); // Valeur mémorisée avec useMemo const nombresFiltres = useMemo(() => { if (!filtreActif) return nombres; // Retourne le tableau original si le filtre n'est pas activé return filtreNombresPairs(nombres); // Sinon, applique le filtre coûteux }, [filtreActif, nombres]); // Recalcule uniquement si "filtreActif" ou "nombres" change function toggleFiltre() { setFiltreActif((prevState) => !prevState); } return ( <div> <h1>Exemple avancé avec useMemo</h1> <button onClick={toggleFiltre}>Activer/Désactiver le filtre</button> <ul> {nombresFiltres.map((nombre) => ( <li key={nombre}>{nombre}</li> ))} </ul> </div> ); } const root = createRoot(document.getElementById('root')); root.render(<App />);
Explication détaillée du code React
Importation des modules nécessaires
On importe React et ses hooks useState
et useMemo
, ainsi que createRoot
de react-dom/client
pour le rendu.
Définition d'une fonction de filtrage
filtreNombresPairs()
est une fonction qui filtre les nombres pairs d'un tableau donné. Elle affiche un message dans la console à chaque exécution.
Définition du composant App
Déclaration du composant fonctionnel App
.
Initialisation des états
Déclaration de l’état nombres
contenant un tableau de nombres de 1 à 10.
Déclaration de l’état filtreActif
, initialisé à false
, indiquant si le filtre des nombres pairs est activé.
Utilisation de useMemo
useMemo
permet de mémoriser le résultat du filtrage. Il est recalculé uniquement si filtreActif
ou nombres
changent :
- Si
filtreActif
estfalse
, on retourne le tableau original. - Sinon, on applique
filtreNombresPairs()
.
Gestion du bouton de filtrage
20-22 : toggleFiltre()
est une fonction qui inverse l’état de filtreActif
lorsqu'on clique sur le bouton.
Rendu du composant
24-30 : Le composant retourne une structure HTML contenant :
- Un titre
<h1>
expliquant l’exemple. - Un bouton qui active/désactive le filtre.
- Une liste affichant soit tous les nombres, soit seulement les nombres pairs selon l'état du filtre.
Montage du composant
32-34 : On récupère l’élément HTML avec document.getElementById('root')
, puis on utilise createRoot
pour y rendre le composant App
.
4. Comparaison entre `useMemo` et d'autres Hooks
Bien que `useMemo` puisse sembler similaire à d'autres Hooks comme `useState` ou `useCallback`, il existe des différences clés qui définissent ses cas d'utilisation spécifiques. Voici une comparaison détaillée :
Hook | Usage | Re-renders Induits | Cas d'Utilisation Typique |
---|---|---|---|
useState |
Gère l'état local d'un composant. | Déclenche un re-render lorsqu'il est mis à jour. | Gestion de valeurs d'état comme un compteur, un texte, etc. |
useCallback |
Mémorise des fonctions pour éviter leur recréation lors des re-renders. | N'émet pas de re-render lui-même, mais peut influencer des enfants optimisés avec React.memo . |
Optimisation des performances pour des fonctions passées via props à des enfants React.memo . |
useMemo |
Mémorise des valeurs calculées pour éviter des recalculs inutiles. | N'émet pas de re-render lui-même. | Optimisation des performances pour des calculs coûteux ou des transformations de données complexes. |
Comme vous pouvez le voir, useMemo
est idéal lorsque vous avez besoin de mémoriser une valeur calculée sans affecter directement le cycle de vie du composant.
5. Meilleures Pratiques pour Utiliser `useMemo`
Pour utiliser useMemo
efficacement, voici quelques conseils pratiques :
- Évitez d'abuser de `useMemo` : Trop de mémorisation peut rendre votre code moins lisible et plus complexe. Utilisez-le uniquement pour des calculs coûteux ou répétitifs.
- Choisissez soigneusement vos dépendances : Incluez uniquement les variables nécessaires dans le tableau de dépendances. Ajouter des dépendances inutiles entraînera des recalculs fréquents, annulant ainsi les avantages de performance.
- Testez avant et après l'optimisation : Mesurez les performances de votre application avant et après avoir appliqué `useMemo`. Cela vous aidera à évaluer si cette optimisation est nécessaire.
6. Exemple Concret : Calcul de la Moyenne dans une Liste de Nombres
Imaginons que vous souhaitez afficher la moyenne d'une liste de nombres. Voici comment utiliser useMemo
pour mémoriser cette valeur calculée et éviter des recalculs inutiles :
import React, { useState, useMemo } from 'react'; import { createRoot } from 'react-dom/client'; function App() { const [nombres, setNombres] = useState([1, 2, 3, 4, 5]); const [filtreActif, setFiltreActif] = useState(false); // Fonction coûteuse pour calculer la moyenne function calculerMoyenne(nombres) { console.log('Calcul de la moyenne...'); if (nombres.length === 0) return 0; const somme = nombres.reduce((total, nombre) => total + nombre, 0); return somme / nombres.length; } // Valeur mémorisée avec useMemo const moyenne = useMemo(() => { if (!filtreActif) return 0; // Si le filtre n'est pas activé, retourne 0 return calculerMoyenne(nombres); // Sinon, calcule la moyenne }, [filtreActif, nombres]); // Recalcule uniquement si "filtreActif" ou "nombres" change function toggleFiltre() { setFiltreActif((prevState) => !prevState); } function ajouterNombre() { setNombres((prevNombres) => [...prevNombres, Math.floor(Math.random() * 100)]); // Ajoute un nombre aléatoire à la liste } return ( <div> <h1>Exemple avancé avec useMemo : Calcul de la moyenne</h1> <button onClick={toggleFiltre}>Activer/Désactiver le calcul</button> <button onClick={ajouterNombre}>Ajouter un nombre aléatoire</button> <p>Filtre actif : {filtreActif ? 'Oui' : 'Non'}</p> <p>Moyenne : {moyenne.toFixed(2)}</p> <ul> {nombres.map((nombre, index) => ( <li key={index}>{nombre}</li> ))} </ul> </div> ); } const root = createRoot(document.getElementById('root')); root.render(<App />);
Explication détaillée ligne par ligne :
-
function calculerMoyenne(nombres) { ... }
:- Cette fonction simule un calcul coûteux en calculant la moyenne d'un tableau de nombres.
console.log('Calcul de la moyenne...');
: Affiche un message dans la console chaque fois que cette fonction est exécutée.nombres.reduce((total, nombre) => total + nombre, 0)
: Utilise la méthodereduce
pour calculer la somme des nombres dans le tableau.somme / nombres.length
: Divise la somme par la longueur du tableau pour obtenir la moyenne.
-
const moyenne = useMemo(() => { ... }, [filtreActif, nombres]);
:- Cette ligne utilise
useMemo
pour mémoriser la valeur de la moyenne. - Le calcul ne sera effectué que si
filteActif
ounombres
change. if (!filtreActif) return 0;
: Si le filtre n'est pas activé, la moyenne est simplement définie à0
, évitant tout calcul coûteux.return calculerMoyenne(nombres);
: Si le filtre est activé, la fonctioncalculerMoyenne
est appelée pour calculer la moyenne.
- Cette ligne utilise
-
function toggleFiltre() { ... }
:- Cette fonction alterne l'état
filteActif
entretrue
etfalse
. - Lorsque ce changement se produit,
useMemo
recalculera la moyenne uniquement sifilteActif
esttrue
.
- Cette fonction alterne l'état
-
function ajouterNombre() { ... }
:- Cette fonction ajoute un nombre aléatoire au tableau
nombres
. Math.floor(Math.random() * 100)
: Génère un nombre entier aléatoire compris entre0
et99
.setNombres((prevNombres) => [...prevNombres, nouveauNombre])
: Met à jour l'étatnombres
en ajoutant le nouveau nombre généré.
- Cette fonction ajoute un nombre aléatoire au tableau
-
<button onClick={toggleFiltre}>Activer/Désactiver le calcul</button>
:- Ce bouton appelle la fonction
toggleFiltre
pour activer/désactiver le calcul de la moyenne. - Lorsque le filtre est désactivé (
false
), aucun calcul n'est effectué grâce àuseMemo
.
- Ce bouton appelle la fonction
-
<button onClick={ajouterNombre}>Ajouter un nombre aléatoire</button>
:- Ce bouton appelle la fonction
ajouterNombre
pour ajouter un nombre aléatoire au tableaunombres
. - Cela déclenche également un recalcul de la moyenne, car
nombres
est une dépendance deuseMemo
.
- Ce bouton appelle la fonction
-
<p>Moyenne : {moyenne.toFixed(2)}</p>
:- Cet élément affiche dynamiquement la moyenne des nombres dans le tableau.
moyenne.toFixed(2)
: Formate la moyenne pour afficher deux chiffres après la virgule.
-
<ul>{nombres.map((nombre, index) => (<li key={index}>{nombre}</li>))}</ul>
:- Cette liste itère sur le tableau
nombres
pour afficher chaque nombre individuellement. key={index}
: Une clé unique est assignée à chaque élément pour aider React à identifier efficacement les changements dans la liste.
- Cette liste itère sur le tableau
7. Quand Utiliser `useMemo` ?
Voici les scénarios où l'utilisation de useMemo
est recommandée :
- Calculs Coûteux : Lorsque vous avez besoin de calculer une valeur complexe ou coûteuse qui ne doit pas être recalculée à chaque re-render.
- Transformations de Données : Par exemple, filtrer, trier ou transformer un grand tableau de données.
- Optimisation des Performances : Si une valeur calculée est utilisée plusieurs fois dans un composant ou transmise à des enfants via props,
useMemo
peut réduire les recalculs inutiles.
Conclusion
Vous avez maintenant appris à utiliser le Hook useMemo
pour mémoriser des valeurs calculées et optimiser les performances de vos applications React. En combinant useMemo
avec des hooks comme useState
et useCallback
, vous pouvez créer des interfaces utilisateur réactives et performantes.
Prochain chapitre : Custom Hooks