Performance React : memo, useMemo, useCallback
Pourquoi Performance React : memo, useMemo, useCallback ?
Dans un monde où la performance est devenue cruciale, chaque micro-optimisation compte. En tant que développeur React avec 10 ans d'expérience, vous savez à quel point le rendu des composants peut être une source constante de frustration. memo, useMemo, et useCallback sont des outils puissants qui permettent d'améliorer la performance en évitant les re-rendus inutiles.
Un cas d'usage concret : imaginez un éditeur de texte grandiosement personnalisable avec une centaine de composants réactifs. Si le rendu de chaque composant était géré sans optimisation, l'éditeur serait lent et frustrant à utiliser. C'est là que memo, useMemo, et useCallback entrent en jeu pour s'assurer que seul ce qui change est mis à jour.
Prerequis
- Connaissances de base de React (Hooks, State, Props)
- Familiarité avec les principes fondamentaux du rendu virtuel de React
- Node.js et npm installés (version recommandée : Node.js 14+)
Concepts fondamentaux
memo
memo est une fonction qui permet de memoiser un composant. Si le props passé au composant n'a pas changé, le composant ne sera pas re-render.
Schema mental :
+-------------------+
| memo |
+----+--------------+------+
| |
v v
+----v--------------v------+
| Composant |
+-------------------+
react
import React, { memo } from 'react';
const MyComponent = memo((props) => {
// Component logic here
return <div>{props.data}</div>;
});
useMemo
useMemo permet de memoiser le résultat d'une fonction. C'est utile pour éviter les calculs coûteux à chaque rendu.
Schema mental :
+-------------------+
| useMemo |
+----+--------------+------+
| |
v v
+----v--------------v------+
| Function |
+-------------------+
react
import React, { useState, useMemo } from 'react';
const MyComponent = ({ data }) => {
const memoizedValue = useMemo(() => {
// Expensive computation here
return data.map(item => item * 2);
}, [data]);
return <div>{memoizedValue.join(', ')}</div>;
};
useCallback
useCallback permet de memoiser une fonction. C'est utile pour éviter les références à des fonctions qui changent à chaque rendu, ce qui peut déclencher des effets secondaires inutiles.
Schema mental :
+-------------------+
| useCallback |
+----+--------------+------+
| |
v v
+----v--------------v------+
| Function |
+-------------------+
react
import React, { useState, useCallback } from 'react';
const MyComponent = ({ onClick }) => {
const memoizedCallback = useCallback(() => {
// Function logic here
onClick();
}, [onClick]);
return <button onClick={memoizedCallback}>Click me</button>;
};
Mise en pratique : projet fil rouge
Étape 1: Configuration du projet
npx create-react-app memo-usememo-usecallback-demo
cd memo-usememo-usecallback-demo
npm start
Étape 2: Création d'un composant Liste
Créez un fichier Liste.js dans le dossier src.
// src/Liste.js
import React, { useState } from 'react';
const Liste = ({ items }) => {
console.log('Rendering Liste');
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
};
export default React.memo(Liste);
Étape 3: Création d'un composant Input
Créez un fichier Input.js dans le dossier src.
// src/Input.js
import React, { useState } from 'react';
const Input = ({ onAddItem }) => {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
if (value.trim()) {
onAddItem(value);
setValue('');
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={value}
onChange={handleChange}
placeholder="Ajouter un item"
/>
<button type="submit">Ajouter</button>
</form>
);
};
export default React.memo(Input);
Étape 4: Utilisation des composants
Modifiez le fichier App.js pour utiliser les composants créés.
// src/App.js
import React, { useState } from 'react';
import Input from './Input';
import Liste from './Liste';
const App = () => {
const [items, setItems] = useState([]);
const addItem = (item) => {
setItems([...items, item]);
};
return (
<div className="App">
<h1>Gestionnaire de Tâches</h1>
<Input onAddItem={addItem} />
<Liste items={items} />
</div>
);
};
export default App;
Erreurs frequentes et debugging
Erreur : Invalid hook call
## ❌ Mauvais
function MyComponent() {
const memoizedValue = useMemo(() => {
return someExpensiveComputation();
}, [someDependency]);
return <div>{memoizedValue}</div>;
}
Correction :
## ✅ Correct
const memoizedValue = useMemo(() => {
return someExpensiveComputation();
}, [someDependency]);
Erreur : React Hook "useMemo" must be called inside a React function component or a custom React Hook function
## ❌ Mauvais
function MyComponent() {
const memoizedValue = useMemo(() => {
return someExpensiveComputation();
}, [someDependency]);
// ... other code ...
if (memoizedValue) {
return <div>{memoizedValue}</div>;
}
}
Correction :
## ✅ Correct
const memoizedValue = useMemo(() => {
return someExpensiveComputation();
}, [someDependency]);
return <div>{memoizedValue}</div>;
Erreur : useMemo and useCallback must be called inside a React function component or a custom React Hook function
## ❌ Mauvais
const memoizedValue = useMemo(() => {
return someExpensiveComputation();
}, [someDependency]);
function MyComponent() {
// ... other code ...
}
Correction :
## ✅ Correct
function MyComponent() {
const memoizedValue = useMemo(() => {
return someExpensiveComputation();
}, [someDependency]);
// ... other code ...
}
Pour aller plus loin
Memoizing Objects and Arrays
- Lire la documentation officielle de React sur la memoisation d'objets et de tableaux.
- React useMemo Documentation
Custom Hooks
- Découvrir comment créer des hooks personnalisés pour réutiliser les logiques complexes.
- React Custom Hooks Tutorial
Performance Analysis with React DevTools
- Utiliser le mode Profiler de React DevTools pour analyser et optimiser la performance de votre application.
- React Performance Tuning Guide
Défi pratique
Défi : Optimisation d'une liste déroulante
Créez un composant Dropdown qui affiche une liste déroulante et utilise useMemo pour éviter les re-rendus inutiles. Assurez-vous que le rendu est optimisé même si la liste contient des milliers d'items.
Piste :
- Utilisez
React.memopour memoiser le composantOption. - Utilisez
useMemopour éviter de recalculer les options à chaque rendu. - Vérifiez le rendu avec React DevTools pour vous assurer que votre optimisation fonctionne.
Conseil : N'oubliez pas d'inclure des commentaires et des instructions claires dans votre code pour aider les autres développeurs à comprendre votre logique.