Comprendre le hook useMemo en React
Où comment traiter les valeurs dérivées en React, et optimiser le rendu de vos composants avec un hook dédié !
Article publié le 02/12/2024, dernière mise à jour le 02/12/2024
En programmation, et notamment dans le monde du front-end, il existe un concept important : celui des valeurs dérivées.
On parle aussi de valeurs calculées (ou “computed values” en anglais)
Une valeur dérivée est simplement une nouvelle donnée, créée à partir d’une ou plusieurs autres données existantes.
Voici un exemple simple :
function getPercentage(value, max){
return Math.round((value / max) * 100) + "%";
}
Ici, à partir de deux valeurs, nous allons créer une troisième valeur dérivée, qui sera le pourcentage sous la forme d’une chaîne de caractère.
Mais alors quel est le problème ?
Les recalculs inutiles avec React
Maintenant ajoutons notre fonction pour calculer une valeur dérivée (pourcentage) dans un composant React très basique :
function MyComponent({ score, time }) {
// Value is between 0 and 10
function getPercentage(value){
return Math.round((value / 10) * 100) + "%";
}
return (
<div>
<p>Time: {time}</p>
<p>Pourcentage: {getPercentage(score)}<p>
</div>
);
}
Et imaginons que la propriété
time
soit mise à jour toutes les 100ms.
La manière dont fonctionne le rendu de React fait que notre composant sera mis à jour toutes les 100ms, et donc notre fonction getPercentage
sera également exécutée toutes les 100ms, même si les paramètres value et max de cette dernière n’ont pas changé de valeur.
Par conséquent le résultat de cette valeur dérivée n’a pas changé non plus, c’est donc un recalcul inutile, qui fait baisser les performances de notre rendu.
Et si il était possible de ne recalculer notre valeur dérivée que lorsque les valeurs utilisées dans le calculs changent ?
Utiliser le hook useMemo
useMemo
est un hook React puissant, conçu pour optimiser les performances en mémorisant le résultat d’une fonction tant que ses dépendances ne changent pas.
Lors du re-rendu d’un composant, React vérifiera les dépendances spécifiées et ne recalculera la valeur que si l’une d’entre elles a changé.
Voici un exemple de base, en reprenant notre fonction précédente :
import { useMemo } from 'react';
function MyComponent({ score, time }) {
const percentage = useMemo(() => {
return Math.round((score / 10) * 100) + "%";
}, [score]);
return (
<div>
<p>Time: {time}</p>
<p>Pourcentage: {percentage}<p>
</div>
);
}
Ici, le pourcentage ne sera recalculée que si
score
change.
Même si le composant est re-rendu toutes les 100ms, notre valeur dérivée percentage
ne sera pas recalculée inutilement.
Quand utiliser useMemo ?
- Pour éviter des calculs inutiles : Si une fonction de calcul est complexe ou dépend d’une grande quantité de données,
useMemo
peut réduire son impact sur les performances. - Dans des composants à re-rendus fréquents : Si un composant re-render souvent à cause d’autres props ou états,
useMemo
peut empêcher des recalculs superflus. - Pour optimiser des opérations coûteuses : Par exemple, le filtrage ou le tri de longues listes, ou encore des calculs mathématiques intensifs.
Exemple avec une opération coûteuse :
function FilteredList({ items }) {
const sortedItems = useMemo(() => {
return items.sort((a, b) => a.score - b.score;
}, [items]);
return <ul>{sortedItems .map(item => <li key={item}>{item}</li>)}</ul>;
}
Quand éviter useMemo ?
Il est important de ne pas abuser de useMemo
.
Si l’opération à optimiser est légère ou si le composant ne se re-render pas fréquemment, useMemo
pourrait ajouter une complexité inutile.
Ce hook a lui-même un coût en termes de gestion mémoire et de vérification des dépendances.
Mais si ce composant dépend d’autres props ou états qui provoquent des re-rendus fréquents, utiliser useMemo
peut prévenir des recalculs inutiles, comme dans notre exemple.
Conclusion
useMemo
est un outil essentiel pour optimiser les performances en React lors de l’utilisation de valeurs dérivées.
Et c’est aussi un très bon moyen de garder le code de votre template le plus propre possible !
Néanmoins pour des calculs simples ou des composants peu sollicités, il n’est pas toujours nécessaire de l’utiliser.
Benoit
12/05/2024, 9:37 PM
Très bien expliqué !
NicolasBrondinBernard
12/06/2024, 9:30 AM
@Benoit Merci 🙏