Communitygithub.com

YepAPI/skills - Défilement Infini

Pagination basée sur curseur, IntersectionObserver, listes virtualisées avec @tanstack/react-virtual et restauration de la position de défilement.

Qu'est-ce que skills - Défilement Infini ?

Ce skill décrit une implémentation complète du défilement infini pour les interfaces utilisateur modernes, conçue pour les développeurs utilisant des frameworks comme React et des librairies comme TanStack Query et @tanstack/react-virtual. Il se concentre sur la pagination basée sur curseur pour éviter les problèmes de duplication ou de saut d'éléments lors d'insertions ou suppressions, contrairement à la pagination par offset. Un IntersectionObserver déclenche le chargement de la page suivante lorsqu'un élément sentinelle devient visible, avec une marge de 100 à 200 pixels pour anticiper le besoin. Pour les listes de plus de 1 000 éléments, la virtualisation DOM est recommandée via @tanstack/react-virtual, ne rendant que les lignes visibles. Le skill inclut également la gestion des états : squelette de chargement, bouton "Charger plus" en fallback, restauration de la position de défilement avec sessionStorage, message de fin de liste et état vide. Il est applicable à tout projet React front-end utilisant ces librairies.

Compatible avec~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/YepAPI/skills/tree/HEAD/skills/infinite-scroll

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Défilement Infini

Règles

  • Pagination basée sur curseur : utilisez l'ID ou le timestamp du dernier élément comme curseur — pas de décalage (offset), qui casse lors des insertions/suppressions.
  • IntersectionObserver : attachez-le à un élément sentinelle en bas de la liste — déclenchez le chargement quand il devient visible.
  • Virtualisation : @tanstack/react-virtual pour les listes de 1 000+ éléments — ne rend que les lignes visibles dans le DOM.
  • Squelette de chargement : affichez des éléments placeholders en bas pendant le chargement de la page suivante — pas de spinner.
  • Bouton "Charger plus" : proposez-le comme alternative pour les utilisateurs qui préfèrent un contrôle manuel ou ont une connexion lente.
  • Restauration de la position de défilement : sauvegardez la position avant la navigation, restaurez-la au retour — utilisez sessionStorage ou l'état du routeur.
  • État vide : affichez un message lorsque la liste ne contient aucun élément — pas une page blanche.
  • Fin de liste : affichez "Vous avez atteint la fin" quand hasNextPage est false — arrêtez l'observateur.

Modèles

// Défilement infini avec React Query + IntersectionObserver
import { useInfiniteQuery } from "@tanstack/react-query";
import { useRef, useEffect } from "react";

function InfiniteList() {
  const sentinelRef = useRef<HTMLDivElement>(null);
  const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({
    queryKey: ["items"],
    queryFn: ({ pageParam }) => fetchItems({ cursor: pageParam, limit: 20 }),
    getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined,
    initialPageParam: undefined as string | undefined,
  });

  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => { if (entries[0].isIntersecting && hasNextPage) fetchNextPage(); },
      { rootMargin: "200px" } // pré-chargement avant d'atteindre le bas
    );
    if (sentinelRef.current) observer.observe(sentinelRef.current);
    return () => observer.disconnect();
  }, [hasNextPage, fetchNextPage]);

  const allItems = data?.pages.flatMap((page) => page.items) ?? [];

  return (
    <div>
      {allItems.map((item) => <ItemCard key={item.id} item={item} />)}
      {isFetchingNextPage && <LoadingSkeleton count={3} />}
      {!hasNextPage && allItems.length > 0 && <p>Vous avez atteint la fin</p>}
      {allItems.length === 0 && !isFetchingNextPage && <EmptyState />}
      <div ref={sentinelRef} />
    </div>
  );
}

// Liste virtualisée pour 10 000+ éléments
import { useVirtualizer } from "@tanstack/react-virtual";

function VirtualList({ items }: { items: Item[] }) {
  const parentRef = useRef<HTMLDivElement>(null);
  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 64, // hauteur estimée d'une ligne en px
    overscan: 5,
  });

  return (
    <div ref={parentRef} style={{ height: "600px", overflow: "auto" }}>
      <div style={{ height: `${virtualizer.getTotalSize()}px`, position: "relative" }}>
        {virtualizer.getVirtualItems().map((virtualRow) => (
          <div key={virtualRow.key} style={{
            position: "absolute", top: 0, left: 0, width: "100%",
            transform: `translateY(${virtualRow.start}px)`,
          }}>
            <ItemCard item={items[virtualRow.index]} />
          </div>
        ))}
      </div>
    </div>
  );
}

À éviter

  • Pagination basée sur offset — les insertions/suppressions décalent tous les offsets, provoquant des doublons ou des éléments manquants.
  • Charger tous les éléments puis filtrer côté client — ne récupérez que la page courante depuis le serveur.
  • Rendre 10 000+ nœuds DOM — utilisez @tanstack/react-virtual pour ne rendre que les lignes visibles.
  • IntersectionObserver sans rootMargin — ajoutez une marge de 100 à 200 pixels pour précharger avant que l'utilisateur n'atteigne le bas.
  • Absence d'indicateur de fin de liste — les utilisateurs doivent savoir qu'il n'y a plus rien à charger.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

YepAPI/skills

WCAG 2.1 AA — semantic HTML, keyboard navigation, screen readers.

YepAPI/skills

Experiment setup, variant splitting, statistical significance, and feature flag integration.

YepAPI/skills

CRUD generators, data tables, user management, role-based access, and bulk operations.

YepAPI/skills

Monitor what ChatGPT and Gemini say about your brand using YepAPI.

YepAPI/skills

Queue workers with BullMQ/Inngest/Trigger.dev, job retries, dead letter queues, concurrency.

YepAPI/skills

Commander.js, interactive prompts with Clack, spinners, colors, config files, exit codes, and npm publishing.

YepAPI/skills

cmdk integration, Cmd+K trigger, fuzzy search, grouped actions, keyboard navigation, and dynamic action registration.

YepAPI/skills

Content planning with trend and sentiment data from YepAPI.

YepAPI/skills

Content calendar, keyword-driven planning, and content briefs.

YepAPI/skills

Theme switching with CSS variables, system preference detection, next-themes, and persistence.

YepAPI/skills

Threaded comments, @mentions, reactions, moderation queue, optimistic UI, and cursor pagination.

YepAPI/skills

Competitive analysis between domains using YepAPI.

YepAPI/skills

Layout grids, KPI cards, data tables with sorting/filtering, sidebar navigation, and responsive breakpoints.

YepAPI/skills

Data encryption — TLS everywhere, AES-256-GCM for PII, bcrypt passwords, encrypted backups.

YepAPI/skills

Chart patterns with Recharts/Nivo/D3, responsive containers, color scales, and accessibility.

YepAPI/skills

Drizzle schema definition, push vs migrate, type-safe queries, relations, transactions, and prepared statements.

YepAPI/skills

Upload handling, resize/compress, CDN delivery, blur placeholders, and next/image patterns.

YepAPI/skills

Local business and Google Maps research using YepAPI.

YepAPI/skills

Tenant isolation (row-level vs schema), subdomain routing, per-tenant config, and data partitioning.

YepAPI/skills

Chat UI components, streaming responses with AI SDK, context window management, and RAG patterns.

Skills associés