Aller au contenu principal
Journal · api

SWR pagination et scroll infini : guide d'optimisation

Découvrez comment utiliser le hook useSWRInfinite de SWR (Vercel) pour implémenter une pagination ou un scroll infini performant et réactif.

D
Équipe Drylead
· 16 oct. 2023· 7 min de lecture
apinextjs
SWR pagination et scroll infini : guide d'optimisation

Chez Drylead, nous intégrons ce type de mécanisme dans les applications que nous développons pour optimiser les performances tout en garantissant une UX irréprochable. Voici comment vous pouvez faire de même.


Pourquoi utiliser SWR pour la pagination ?

SWR (stale-while-revalidate) est une bibliothèque de gestion des données développée par Vercel, l'équipe derrière Next.js. Son nom provient d'une stratégie de cache HTTP : afficher d'abord les données en cache (stale), puis revalider en arrière-plan pour les mettre à jour. Cette approche offre une réactivité immédiate à l'utilisateur tout en garantissant la fraîcheur des données.

Pour la pagination et le scroll infini, SWR propose le hook useSWRInfinite, spécialement conçu pour charger des données au fur et à mesure — que ce soit via un bouton "Charger plus" ou un déclenchement automatique au scroll. Les avantages sont nombreux :

  • Cache intelligent : les pages déjà chargées sont conservées en mémoire, évitant des requêtes réseau inutiles

  • Revalidation automatique : les données sont rafraîchies en arrière-plan quand l'utilisateur revient sur l'onglet

  • Gestion d'erreur native : retry automatique en cas d'échec réseau

  • Déduplication des requêtes : si plusieurs composants demandent les mêmes données, une seule requête est envoyée

  • Légèreté : seulement ~4 KB gzippé, sans dépendance externe

Comparé à des solutions comme React Query ou une implémentation manuelle avec useEffect, SWR offre un excellent équilibre entre simplicité et puissance, particulièrement dans un écosystème Next.js.


Étape 1 : Installer SWR dans votre projet React

Si ce n'est pas encore fait, ajoutez SWR à votre projet :

npm install swr
# ou
yarn add swr

SWR est compatible avec React 16.11+, Next.js, et fonctionne aussi bien en SSR qu'en CSR. Aucune configuration globale n'est nécessaire pour démarrer, bien qu'un SWRConfig au niveau de votre application permette de définir des options par défaut (fetcher, intervalle de revalidation, etc.).

Étape 2 : Configurer le fetcher et la fonction de récupération

SWR nécessite une fonction fetcher qui prend une URL en paramètre et retourne les données. Voici un exemple basé sur Axios, mais vous pouvez utiliser fetch ou toute autre bibliothèque HTTP :

import useSWRInfinite from 'swr/infinite';
import axios from 'axios';

// Fetcher générique — réutilisable dans tout votre projet
const fetcher = (url) => axios.get(url).then((res) => res.data);

// Vous pouvez aussi passer des headers d'authentification
const authenticatedFetcher = (url) =>
  axios.get(url, {
    headers: { Authorization: `Bearer ${token}` }
  }).then((res) => res.data);

Le fetcher est la pierre angulaire de SWR. En le définissant une seule fois (par exemple dans un SWRConfig global), vous n'avez plus à le passer à chaque appel. C'est une bonne pratique qui simplifie votre code et centralise la logique d'appel API.

Étape 3 : Implémenter useSWRInfinite

Le hook useSWRInfinite est le cœur du mécanisme. Il gère automatiquement l'index de page et l'accumulation des résultats :

const PAGE_SIZE = 10;

const getKey = (pageIndex, previousPageData) => {
  // Retourner null signale qu'il n'y a plus de données à charger
  if (previousPageData && !previousPageData.length) return null;

  // La clé est l'URL de la page à charger (pageIndex commence à 0)
  return \`/api/data?page=\${pageIndex + 1}&limit=\${PAGE_SIZE}\`;
};

const { data, error, size, setSize, isValidating, mutate } =
  useSWRInfinite(getKey, fetcher, {
    initialSize: 1,           // Nombre de pages chargées initialement
    revalidateFirstPage: true, // Revalider la première page à chaque changement
    persistSize: false,        // Réinitialiser la taille quand la clé change
  });

// États dérivés utiles
const isLoadingInitialData = !data && !error;
const isLoadingMore =
  isLoadingInitialData ||
  (size > 0 && data && typeof data[size - 1] === 'undefined');
const isEmpty = data?.[0]?.length === 0;
const isReachingEnd =
  isEmpty || (data && data[data.length - 1]?.length < PAGE_SIZE);
const isRefreshing = isValidating && data && data.length === size;

Quelques points importants à retenir :

  • La fonction getKey reçoit l'index de la page et les données de la page précédente. Retourner null indique qu'il n'y a plus de pages.

  • size représente le nombre de pages actuellement chargées. setSize permet d'en demander plus.

  • mutate permet de revalider manuellement les données (utile après une modification côté serveur).

  • L'état isReachingEnd est essentiel pour masquer le bouton "Charger plus" quand toutes les données sont affichées.

Étape 4 : Affichage dans le composant

L'intégration dans votre composant React est straightforward. Voici un exemple complet avec gestion des états de chargement et d'erreur :

if (error) return 
Erreur : {error.message}
; if (!data) return
Chargement...
; const allData = [].concat(...data); return (
{allData.map((item) => (
{/* Rendu de vos données ici */}
))} {/* Indicateur de chargement pour les pages suivantes */} {isLoadingMore &&
Chargement de plus de données...
} {/* Bouton charger plus — masqué quand on atteint la fin */} {!isReachingEnd && ( setSize(size + 1)} disabled={isLoadingMore}> Charger plus )} {/* Message quand toutes les données sont affichées */} {isReachingEnd && !isEmpty && (

Toutes les données ont été chargées.

)}
);

Aller plus loin : le scroll infini avec Intersection Observer

Pour transformer le bouton "Charger plus" en un véritable scroll infini, combinez useSWRInfinite avec l'API IntersectionObserver. Le principe : détecter quand un élément sentinelle devient visible dans le viewport, puis charger automatiquement la page suivante.

import { useRef, useEffect, useCallback } from 'react';

const sentinelRef = useRef(null);

const handleIntersect = useCallback(
  (entries) => {
    if (entries[0].isIntersecting && !isLoadingMore && !isReachingEnd) {
      setSize((prev) => prev + 1);
    }
  },
  [isLoadingMore, isReachingEnd, setSize]
);

useEffect(() => {
  const observer = new IntersectionObserver(handleIntersect, {
    rootMargin: '200px', // Déclenche 200px avant que l'élément soit visible
  });
  if (sentinelRef.current) observer.observe(sentinelRef.current);
  return () => observer.disconnect();
}, [handleIntersect]);

// Dans votre JSX, ajoutez la sentinelle après la liste
// 

Le rootMargin de 200px déclenche le chargement légèrement en avance, ce qui donne l'illusion d'une liste infinie sans temps d'attente perceptible. C'est exactement le pattern utilisé par les grandes applications comme Twitter, Instagram ou LinkedIn.


Bonnes pratiques et pièges à éviter

Voici quelques recommandations issues de notre expérience chez Drylead :

  • Définissez un PAGE_SIZE adapté : trop petit (5) génère trop de requêtes, trop grand (100) ralentit le rendu. Visez 10 à 25 selon la complexité de vos items.

  • Ajoutez un skeleton loader : plutôt qu'un simple texte "Chargement...", affichez des placeholders qui reproduisent la structure des éléments à venir.

  • Gérez la navigation retour : quand l'utilisateur quitte la page puis revient, SWR restaure les données depuis le cache. Vérifiez que le scroll position est aussi restauré.

  • Attention au re-render excessif : si votre liste est longue, envisagez la virtualisation (react-window ou react-virtuoso) pour ne rendre que les éléments visibles.

  • Côté API : retournez toujours un indicateur de fin (tableau vide ou champ hasMore) pour que le frontend sache quand arrêter de paginer.


Cas d'usage idéaux

Ce système de pagination SWR est particulièrement adapté pour :

  • Les interfaces d'administration affichant des listes de clients, commandes ou tickets

  • Les applications mobiles en React Native où le scroll infini est le pattern dominant

  • Les e-commerces affichant des catalogues produits avec filtres dynamiques

  • Les back-offices sur mesure avec des tableaux de données complexes

  • Les feeds de contenu (actualités, articles, notifications) où le chargement progressif est essentiel


Besoin d'aller plus loin ? On le fait pour vous.

Chez Drylead, nous accompagnons les entreprises ambitieuses dans la création d'interfaces modernes, rapides et scalables avec React, Next.js et SWR. Nous utilisons quotidiennement ces technologies dans nos projets clients, et nous maîtrisons les subtilités qui font la différence entre une implémentation basique et une expérience utilisateur professionnelle.

Vous avez un besoin spécifique ? Que ce soit pour auditer votre front-end existant, migrer vers Next.js, ou développer une application sur mesure, notre équipe technique est prête à vous accompagner.

Contactez-nous pour bénéficier d'un accompagnement technique sur-mesure : développement, audit de performance, migration vers Next.js... On s'occupe de tout.

Parlons-en : contact

Plus d'infos sur : drylead.agency

Partager cette note
Twitter / XLinkedIn

Vous aussi vous voulez bosser avec nous.

Pas d'engagement long, pas de package premium magique. On regarde votre cas, on dit ce qu'on peut faire, on chiffre. Vous décidez.