Virtualiser les grandes listes de données facilement avec react-window
Gérer efficacement de grandes listes de données peut rapidement devenir très compliqué dans une application React : plus il y a de données à afficher, plus les performances seront impactées.
Quand des milliers d'éléments doivent être affichés (comme une liste des utilisateurs inscrits ou une liste d'articles) : c'est catastrophique pour l'expérience utilisateur, avec un navigateur qui tente de tenir le rythme et finit par planter une fois sur trois. 🥲
Heureusement, une existe une solution : react-window ✨
Il s'agit d'une librairie React très pratique pour gérer de grandes quantités de données. On parle de virtualisation.
Quand on parle de virtualiser quelque chose, ceci veut dire qu'on ne va afficher à l'écran qu'une petite partie d'éléments visibles dans le viewport (la fenêtre du navigateur).
La virtualisation a plusieurs avantages :
- Réduire le chargement de la page car les données chargées sont uniquement les données visibles directement sur l'écran par l'utilisateur ;
- Améliorer la fluidité car moins de données sont présentes dans le DOM et donc le navigateur a moins besoin de travailler pour défiler sur une page ;
- Booster l'expérience utilisateur car il se retrouve avec une page rapide à charger.
Pourquoi utiliser react-window ?
Les avantages de react-window sont nombreux pour les développeurs React qui doivent gérer de grandes quantités de données dans leur projet :
- Hyper léger et très rapide - Si on compare react-window à d'autres librairies comme react-virtualized avec qui elle est souvent comparée (on fait un point dessus juste après), react-window est beaucoup plus léger ;
- Des performances améliorées - Activer la virtualisation permet, comme nous l'avons vu, d'amléiorer grandement les performances de chargement d'une page (et ça on aime !) ;
- Supporte différents types de listes - Sous forme de grilles, de listes horizontales ou verticales, tout est supporté par react-window sans aucun problème.
Installer react-window
Pour commencer à utiliser react-window, il vous faut un projet réalisé avec React (sans blague 🙃).
Une fois que c'est fait, il suffit d'installer la librairie avec npm :
npm install react-window
Ou si vous préférez yarn :
yarn add react-window
Créer une liste avec react-window
Les listes sont les formats les plus utilisés pour afficher des données. Elles permettent d'ajouter tous les éléments un par un les uns en-dessous des autres.
Créer une liste de taille fixe avec FixedSizeList
Le composant principal de react-window est le composant FixedSizeList
. Il permet d'afficher une liste d'éléments de taille fixe.
Voyons un petit exemple :
import React from 'react';
import { FixedSizeList as List } from 'react-window';
const items = Array(5000).fill().map((_, index) => `Item ${index + 1}`);
function Row({ index, style }) {
return (
<div style={style}>
{items[index]}
</div>
);
}
export default function App() {
return (
<List
height={500}
itemCount={items.length}
itemSize={40}
width={500}
>
{Row}
</List>
);
}
Dans cet exemple, nous utilisons une liste 5000 éléments (Array(5000)
) que nous remplissons pour donner une liste générique avec laquelle nous pouvons travailler.
["Item 1","Item 2","Item 3","Item 4","Item 5","Item 6","Item 7","Item 8","Item 9","Item 10","Item 11","Item 12","Item 13", ...]
Nous utilisons ensuite le composant FixedSizeList
renommé List
selon les bonnes pratiques :
height
- définit la hauteur de la liste visibleitemCount
- le nombre d'éléments de notre liste complèteitemSize
- la hauteur de chaque élémentwidth
- définit la largeur de la liste visible également
Grâce au composant FixedSizeList
, nous avons désormais une liste de 5000 éléments qui s'affiche en un claquement de doigts !
Si vous préférez afficher une liste horizontale donc qui permet de défiler comme avec un slider (à la Netflix) vous pouvez aussi le faire ! Il suffit d'ajouter la propriété
layout
:JSX<List height={500} itemCount={items.length} itemSize={40} width={500} layout="horizontal" > {Row} </List>
Créer une liste de taille variable avec VariableSizeList
Souvent, nos éléments n'ont pas une taille fixe : nous ne pouvons donc pas utiliser FixedSizeList
.
Heureusement, une autre possibilité offerte par react-window est d'utiliser le composant VariableSizeList
(le nom parle de lui-même 😋).
Ce composant permet de gérer des tailles variables. En voici un exemple :
import React from 'react';
import { VariableSizeList as List } from 'react-window';
const items = Array(5000).fill().map((_, index) => `Item ${index + 1}`);
function getItemSize(index) {
return 30 + (index % 10) * 10; // Exemple de taille variable
}
function Row({ index, style }) {
return (
<div style={style}>
{items[index]}
</div>
);
}
export default function App() {
return (
<List
height={500}
itemCount={items.length}
itemSize={getItemSize}
width={500}
>
{Row}
</List>
);
}
Dans cet exemple, tous les éléments de notre liste ont une taille différente calculée grâce à la fonction getItemSize
.
Comme pour
FixedSizeList
vous pouvez demander à avoir une disposition horizontale en précisantlayout="horizontal"
🙂
Créer des grilles avec react-window
En plus des listes, react-window permet de gérer des grilles de données avec les composants FixedSizeGrid
et VariableSizeGrid
. Présentés sous forme de tableaux, ces composants sont très utiles pour afficher des données avec des lignes et des colonnes.
Créer une grille de taille fixe avec FixedSizeGrid
Voici comment créer une grille de taille fixe avec react-window :
import React from 'react';
import { FixedSizeGrid as Grid } from 'react-window';
function Cell({ columnIndex, rowIndex, style }) {
return (
<div style={style}>
{`Ligne ${rowIndex}, Colonne ${columnIndex}`}
</div>
);
}
export default function App() {
return (
<Grid
columnCount={100}
columnWidth={100}
height={500}
rowCount={100}
rowHeight={35}
width={500}
>
{Cell}
</Grid>
);
}
Dans cet exemple, une grille de 100 cellules de long par 100 cellules de large est affichée ! Ceci pourrait provoquer quelques ralentissements pour le navigateur, mais pas avec react-window qui ne charge que les cellules qui sont visibles à l'écran.
Pour aller dans le détail :
columCount
- cette propriété précise le nombre total de colonnes dans la grille (ici 100 colonnes) ;columnWith
- spécifie la largeur de chaque colonne en pixels (100 pixels dans l'exemple) ;height
- indique la hauteur totale de la grille en pixels ;rowCount
- spécifie le nombre de lignes dans la ligne ;rowHeight
- définit la hauteur de chaque ligne en pixels ;width
- indique la largeur totale de la grille en pixels.
Grâce à ces paramètres, la grille va afficher un sous-ensemble des éléments.
Seules les 5 colonnes (100 pixels chacune) sur les 100 colonnes totales seront visibles à un moment donné. Lorsque l'utilisateur fait défiler horizontalement, de nouvelles colonnes seront rendues dans le DOM.
De même, seules 14 lignes (35 pixels chacune) parmi les 100 lignes seront visibles à un moment donné dans la fenêtre (puisqu'elle fait 500 pixels de hauteur).
Avec un exemple réel voici ce que nous pourrions avoir pour afficher nos utilisateurs inscrits sur notre site internet :
import React from 'react';
import { FixedSizeGrid as Grid } from 'react-window';
const utilisateurs = [
{ utilisateurId: 1, prenom: 'John', nom: 'Doe' },
{ utilisateurId: 2, prenom: 'Jane', nom: 'Smith' },
{ utilisateurId: 3, prenom: 'Paul', nom: 'Johnson' },
// etc
];
// Nombre de colonnes (id, prénom, nom)
const columnCount = 3;
// Largeur de chaque colonne
const columnWidth = 150;
// Hauteur de chaque ligne
const rowHeight = 40;
// Largeur totale visible de la grille (basé sur 3 colonnes)
const gridWidth = columnCount * columnWidth;
// Hauteur totale visible de la grille (exemple de 6 lignes visibles)
const gridHeight = 6 * rowHeight;
function Cell({ columnIndex, rowIndex, style }) {
const utilisateur = utilisateurs[rowIndex];
// Détermine quel contenu afficher selon l'indice de la colonne
let content;
switch (columnIndex) {
case 0:
content = utilisateur.id;
break;
case 1:
content = utilisateur.prenom;
break;
case 2:
content = utilisateur.nom;
break;
default:
content = '';
}
return (
<div style={style}>
{content}
</div>
);
}
export default function App() {
return (
<Grid
columnCount={columnCount}
columnWidth={columnWidth}
height={gridHeight}
rowCount={utilisateurs.length}
rowHeight={rowHeight}
width={gridWidth}
>
{Cell}
</Grid>
);
}
Dans cet exemple, toutes les lignes sont expliquées pour que vous puissiez vous y retrouver. Ce que vous devez retenir, c'est qu'il suffit d'utiliser l'index de l'élément pour placer correctement les informations qui y sont associées (ici sur un utilisateur). 😬
Créer une grille de taille variable avec VariableSizeGrid
Pour travailler avec des éléments de tailles variables dans une grille, vous pouvez utiliser le composant VariableSizeGrid
proposée par react-window.
Dans cet exemple, nous allons utiliser des colonnes pour afficher id
, prenom
, et nom
(j'ai fais exprès d'utiliser du français pour rendre ce sujet un petit plus complexe accessible au plus grand nombre 😋), mais chaque colonne et chaque ligne aura une taille différente, ce qui est géré par VariableSizeGrid
.
import React, { useRef } from 'react';
import { VariableSizeGrid as Grid } from 'react-window';
// Exemple de données utilisateurs
const utilisateurs = [
{ utilisateurId: 1, prenom: 'John', nom: 'Doe' },
{ utilisateurId: 2, prenom: 'Jane', nom: 'Smith' },
{ utilisateurId: 3, prenom: 'Paul', nom: 'Johnson' },
// etc
];
// Fonction pour retourner la largeur de chaque colonne dynamiquement
const getColumnWidth = (index) => {
switch (index) {
case 0: // id
return 100;
case 1: // prénom
return 150;
case 2: // nom
return 200;
default:
return 100;
}
};
// Fonction pour retourner la hauteur de chaque ligne
const getRowHeight = (index) => {
return 40 + (index % 3) * 10; // Ici avec une hauteur variable
};
function Cell({ columnIndex, rowIndex, style }) {
const utilisateur = utilisateurs[rowIndex];
// Détermine quel contenu afficher selon l'index
let content;
switch (columnIndex) {
case 0:
content = utilisateur.id;
break;
case 1:
content = utilisateur.prenom;
break;
case 2:
content = utilisateur.nom;
break;
default:
content = '';
}
return (
<div style={style}>
{content}
</div>
);
}
export default function App() {
return (
<Grid
columnCount={3} // Trois colonnes : id, prénom, nom
columnWidth={getColumnWidth} // Largeur des colonnes définie dynamiquement
height={400} // Hauteur visible de la grille
rowCount={utilisateurs.length} // Nombre de lignes = nombre d'utilisateurs
rowHeight={getRowHeight} // Hauteur des lignes définie dynamiquement
width={500} // Largeur visible de la grille
>
{Cell}
</Grid>
);
}
Dans cet exemple, tous nos utilisateurs ont une hauteur différente calculée par getRowHeight
et une largeur de celulle différente calculée selon l'information à afficher : id
, prenom
ou nom
.
Conclusion
React-window est vraiment une solution puissante et légère pour gérer sans difficultés de grandes listes de données !
Comme nous l'avons vu, la librairie peut tout aussi bien gérer l'affichage des listes que des tableaux.
Bien que sa maîtrise demande un peu de temps, c'est un vrai must-have pour tous les projets soucieux d'améliorer l'expérience utilisateur.
FAQ
On a condensé pour vous les questions les plus fréquentes que nos apprenants nous posent quand ils nous parlent de react-window ! 😬
Quelle est la différence entre react-window et react-virtualized ?
On compare souvent les deux ! react-window est plus léger et plus performant pour la plupart des cas d’utilisation. react-virtualized offre plus de fonctionnalités, mais est beaucoup plus complexe à mettre en place et est également plus lourd : ce qui va à l'encontre de ce que nous cherchons.
Créé par le même développeur, react-virtualized est le premier-né, ce n'est qu'après que react-window a vu le jour pour contrebalancer la complexité de react-virtualized.
Donc si vous voulez un petit conseil : utilisez reac-window plutôt que react-virtualized. 😉
Quels sont les avantages de la virtualisation ?
La virtualisation permet de rendre uniquement les éléments visibles dans votre DOM, ce qui améliore les performances, notamment lors du rendu de longues listes.
Quelle taille maximale est autorisée pour utiliser react-window ?
En fait il n'y en a aucune ! Vous pouvez utiliser react-window pour autant de données que vous le souhaitez.
Est-il possible de récupérer les données au fur et à mesure que l'utilisateur scrolle dans la liste ?
Oui ! Avec une librairie développée par le développeur de react-window : react-window-infinite-loader.
Je veux continuer à apprendre React, quelle formation choisir ? 🤔
La notre bien entendu ! 🙄