
Virtualisation des listes longues (react-window, react-virtualized)
Apprenez à utiliser la virtualisation (windowing) avec des bibliothèques comme react-window pour afficher efficacement de longues listes en React et améliorer drastiquement les performances.
Le défi des listes interminables : Quand le DOM sature
Afficher des listes d'éléments est une tâche courante dans les applications web. Cependant, lorsque ces listes deviennent très longues – contenant des centaines, voire des milliers d'items (pensez à un flux d'actualités infini, une grande table de données, une liste de contacts étendue) – l'approche de rendu classique consistant à générer un noeud DOM pour chaque item pose de sérieux problèmes de performance.
Chaque élément ajouté au DOM consomme de la mémoire et augmente le temps nécessaire au navigateur pour calculer la mise en page, appliquer les styles et effectuer le rendu. Même avec des optimisations comme `React.memo`, si des milliers d'éléments doivent être rendus initialement, l'application peut devenir extrêmement lente, voire ne plus répondre. Le temps de chargement initial explose, et les interactions comme le défilement (scroll) deviennent saccadées car le navigateur peine à gérer le grand nombre d'éléments.
Face à cette limitation fondamentale, une technique d'optimisation spécifique a été développée : la virtualisation, aussi appelée "windowing".
Le principe de la virtualisation : Ne rendre que le visible
L'idée maîtresse de la virtualisation est simple mais puissante : au lieu de rendre tous les éléments de la liste dans le DOM, on ne rend que la petite portion d'éléments qui sont actuellement visibles (ou sur le point de devenir visibles) dans la "fenêtre" (viewport) de l'utilisateur.
Comment cela fonctionne-t-il ? Une bibliothèque de virtualisation calcule, en fonction de la position de défilement actuelle, de la taille de la zone visible (la "fenêtre") et de la taille de chaque élément de la liste, quels sont les indices des éléments qui devraient être affichés. Elle crée ensuite un conteneur de la taille totale de la liste (pour que la barre de défilement soit correcte) et positionne absolument, à l'intérieur de ce conteneur, uniquement les quelques éléments qui doivent être visibles à ce moment précis.
Lorsque l'utilisateur fait défiler la liste, la bibliothèque recalcule les éléments visibles et met à jour dynamiquement le petit sous-ensemble d'éléments rendus dans le DOM, en ajustant leur position. Le résultat est une amélioration spectaculaire des performances : que la liste contienne 100 ou 100 000 éléments, le nombre d'éléments réellement présents dans le DOM reste faible et constant, rendant le défilement fluide et la consommation mémoire maîtrisée.
Bibliothèques populaires : `react-window` et `react-virtualized`
Implémenter la virtualisation manuellement est complexe. Heureusement, plusieurs bibliothèques populaires s'en chargent pour nous dans l'écosystème React :
react-window: Une bibliothèque moderne, légère et performante, créée par l'auteur original de `react-virtualized`. Elle se concentre sur l'essentiel et fournit des composants optimisés pour les cas d'usage courants de listes et de grilles à taille fixe ou variable (`FixedSizeList`, `VariableSizeList`, `FixedSizeGrid`, `VariableSizeGrid`). C'est souvent le choix recommandé pour de nouveaux projets grâce à sa taille réduite et ses performances.react-virtualized: La bibliothèque historique et plus complète. Elle offre une plus grande variété de composants (List,Grid,Table,Collection,Masonry) et plus d'options de configuration, mais elle est significativement plus volumineuse que `react-window`. Elle reste une option valide si vous avez besoin de fonctionnalités plus avancées qu'elle seule propose.
Ces bibliothèques fournissent des composants qui remplacent la manière dont vous itérez habituellement pour rendre une liste (par exemple, un `.map()` direct sur un grand tableau).
Exemple basique avec `react-window` (`FixedSizeList`)
Voyons comment implémenter une liste virtualisée simple avec des éléments de taille fixe en utilisant `react-window`. D'abord, installez la bibliothèque :
npm install react-window
# ou
yarn add react-windowEnsuite, utilisez le composant `FixedSizeList` :
import React from 'react';
import { FixedSizeList as List } from 'react-window';
// Supposons que 'items' est un très grand tableau d'objets { id, text }
// const items = Array.from({ length: 10000 }, (_, index) => ({ id: index, text: `Item ${index + 1}` }));
// Votre composant qui rend chaque ligne de la liste
// Il reçoit 'index' et 'style' en props
const Row = ({ index, style, data }) => {
const item = data[index];
// !!! Important: Appliquer le style fourni par react-window
return (
{item.text}
);
};
function MaListeTresLongue({ items }) {
return (
{Row} { /* Passer le composant Row comme enfant (render prop) */}
);
}
// Utilisation
//
export default MaListeTresLongue;
Points clés :
- On importe `FixedSizeList` (ici renommé `List`).
- On lui fournit la `height` et la `width` de la zone de défilement.
- `itemCount` indique le nombre total d'éléments.
- `itemSize` spécifie la hauteur fixe de chaque ligne.
- Le composant enfant (`Row`) est passé en tant que prop `children`. Il reçoit automatiquement `index` (l'indice de l'élément à rendre) et `style` (un objet de style contenant `top`, `left`, `width`, `height` calculés par `react-window`).
- Il est essentiel d'appliquer l'objet `style` reçu à l'élément racine rendu par `Row` pour que la virtualisation fonctionne correctement.
- On utilise `itemData` pour passer des données supplémentaires (ici, le tableau `items`) au composant `Row`.
Même si `items` contient 10 000 éléments, `react-window` ne rendra qu'environ 8-10 composants `Row` dans le DOM à la fois (assez pour remplir 400px de hauteur avec des items de 50px), rendant l'affichage et le défilement extrêmement rapides.
Considérations et quand virtualiser
La virtualisation est une technique d'optimisation très efficace, mais elle introduit aussi une certaine complexité :
- Taille des éléments : La gestion est plus simple avec des éléments de taille fixe (`FixedSizeList`). Si vos éléments ont des tailles variables, vous devez utiliser `VariableSizeList` et fournir une fonction `itemSize` qui peut estimer ou calculer la taille de chaque élément, ce qui peut être plus complexe.
- Accessibilité (a11y) : Comme seuls quelques éléments sont dans le DOM, il faut parfois un travail supplémentaire pour s'assurer que la liste reste navigable pour les lecteurs d'écran ou la navigation au clavier. Les bibliothèques modernes font des efforts dans ce sens, mais c'est un point à vérifier.
- Mise en page complexe : Si chaque élément de la liste a une structure interne très dynamique ou complexe, ou interagit fortement avec ses voisins, la virtualisation peut être plus difficile à implémenter correctement.
- Recherche "Find" du navigateur : La fonction de recherche native du navigateur (Ctrl+F / Cmd+F) ne fonctionnera que sur les éléments actuellement rendus dans le DOM.
Quand utiliser la virtualisation ? Elle est principalement justifiée lorsque vous devez afficher des listes ou des grilles contenant un grand nombre d'éléments (typiquement, plusieurs centaines ou milliers) et que vous constatez des problèmes de performance au rendu initial ou lors du défilement. Pour des listes courtes ou de taille moyenne, le coût et la complexité de la virtualisation ne sont généralement pas nécessaires.
En conclusion, la virtualisation est une technique d'optimisation indispensable pour gérer efficacement l'affichage de grandes quantités de données en React. Des bibliothèques comme `react-window` rendent son implémentation accessible et permettent d'obtenir des gains de performance spectaculaires pour les listes et grilles longues.