Believemy logo purple

Virtualiser les grandes listes de données facilement avec react-window

Découvrez comment virtualiser efficacement de grandes listes de données en utilisant react-window et améliorer l'expérience de vos utilisateurs.
Mis à jour le 3 décembre 2024
Believemy logo

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 :

  1. 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 ;
  2. 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 ;
  3. 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 :

  1. 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 ;
  2. 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 !) ;
  3. 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 :

CONSOLE
npm install react-window

Ou si vous préférez yarn :

CONSOLE
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 :

JSX
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.

CONSOLE
["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 visible
  • itemCount - le nombre d'éléments de notre liste complète
  • itemSize - la hauteur de chaque élément
  • width - 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 :

JSX
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écisant layout="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 :

JSX
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 :

JSX
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.

JSX
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 ! 🙄

Catégorie : Développement
Believemy logo
Commentaires (0)

Vous devez être connecté pour commenter cet article : se connecter ou s'inscrire.

Essayez gratuitement

Que vous essayiez de scaler votre start-up, de créer votre premier site internet ou de vous reconvertir en tant que développeur, Believemy est votre nouvelle maison. Rejoignez-nous, évoluez et construisons ensemble votre projet.

Believemy is with anyone