Maison >interface Web >js tutoriel >Comment utiliser les requêtes Infinity (TanStack Query) pour effectuer un défilement infini

Comment utiliser les requêtes Infinity (TanStack Query) pour effectuer un défilement infini

Mary-Kate Olsen
Mary-Kate Olsenoriginal
2024-11-10 10:01:02624parcourir

Voici votre message traduit en anglais :


Dans cet article, je vais vous apprendre à implémenter le défilement infini à l'aide de TanStack Query, en particulier avec Infinity Queries. Nous allons créer un flux photo avec Vite et mettre en place un défilement infini. Pour commencer, ouvrez votre terminal et exécutez la commande suivante pour cloner un projet avec des configurations de base :

git clone --branch start https://github.com/DAVI-REZENDE/photos-feed.git

cd photos-feed
npm i

Tout est prêt ! Maintenant, implémentons la fonctionnalité de défilement infini à l'aide de la bibliothèque TanStack Query. Installez-le avec la commande ci-dessous :

npm i @tanstack/react-query
npm i axios

Dans le fichier App.tsx, vous verrez que votre code ressemble à ceci :

How to use Infinity Queries (TanStack Query) to do infinite scrolling

Tout d’abord, nous allons remplacer useEffect par useInfiniteQuery, le hook chargé de gérer nos requêtes infinies. Nous devons lui fournir deux propriétés : queryKey et queryFn, comme suit :

const { 
  data, 
  isLoading,
  fetchNextPage,
  isFetchingNextPage, 
  isFetching, 
  hasNextPage 
} = useInfiniteQuery({
    queryFn: fetchPhotos,
    queryKey: ['photos'],
    initialPageParam: 1,
    getNextPageParam: (lastPage) => {
      return lastPage.nextPage
    }
})

Explication de chaque paramètre :

  • queryFn : la fonction chargée de renvoyer les données de notre requête ; il reçoit la page courante en paramètre.
  • queryKey : sert d'identifiant pour votre requête, agissant également comme un tableau de dépendances. Chaque fois qu'une variable que vous y transmettez change, useInfiniteQuery la récupère automatiquement.
  • initialPageParam : la valeur initiale par défaut.
  • getNextPageParam : reçoit tout ce que renvoie votre fonction queryFn et doit renvoyer le numéro de page suivant à demander.

Nous devrons modifier la fonction fetchPhotos :

async function fetchPhotos({ pageParam }: { pageParam: number }) {
  const response = await api.get<ImageData[]>('/photos', {
    params: {
      page: pageParam,
      per_page: 5,
    }
  })

  return {
    data: response.data,
    nextPage: pageParam + 1
  }
} 

Le hook useInfiniteQuery renvoie les données en pages, donc notre rendu changera légèrement :

<main className="h-screen w-screen bg-zinc-950 flex flex-col gap-6 p-6 items-center text-white overflow-auto">
  {isLoading ? 'Loading...' : (
    <>
      {data?.pages.map((group, i) => (
        <div className="flex flex-col gap-6" key={i}>
          {group.data.map(({ id, urls }) => (
            <img className="aspect-square rounded-md h-[550px] object-cover" src={urls.regular} key={id} />
          ))}
        </div>
      ))}
      <div>
        <button
          onClick={() => fetchNextPage()}
          disabled={!hasNextPage || isFetchingNextPage}
        >
          {isFetchingNextPage
            ? 'Loading more...'
            : hasNextPage
              ? 'Load More'
              : 'Nothing more to load'}
        </button>
      </div>
      <div>{isFetching && !isFetchingNextPage ? 'Fetching...' : null}</div>
    </>
  )}
</main>

Désormais, chaque fois que l'utilisateur atteint la fin du parchemin et clique sur le bouton « Charger plus », les données seront automatiquement ajoutées.

Pour récupérer la page suivante chaque fois que l'utilisateur atteint la fin du défilement sans avoir besoin de cliquer sur le bouton, ajoutez simplement la fonction suivante :

function handleScroll(event: UIEvent<HTMLElement>) {
  const { scrollTop, clientHeight, scrollHeight } = event.currentTarget

  if (scrollTop + clientHeight >= scrollHeight) {
    fetchNextPage()
  }
}

Et ajoutez l'événement onScroll dans le div qui enveloppe votre liste, en appelant la fonction ici. Fait! Désormais, chaque fois que l'utilisateur fait défiler jusqu'à la fin, de nouvelles données seront automatiquement chargées.

Au final, votre code devrait ressembler à ceci :

import { useInfiniteQuery } from "@tanstack/react-query"
import { UIEvent } from "react"
import { api } from "./lib/api"

type ImageData = {
  id: string,
  urls: {
    regular: string
  }
}

export function Home() {
  async function fetchPhotos({ pageParam }: { pageParam: number }) {
    const response = await api.get<ImageData[]>('/photos', {
      params: {
        page: pageParam,
        per_page: 5,
      }
    })

    return {
      data: response.data,
      nextPage: pageParam + 1
    }
  } 

  const { data, isLoading, fetchNextPage, isFetchingNextPage, isFetching, hasNextPage } = useInfiniteQuery({
    queryFn: fetchPhotos,
    queryKey: ['photos'],
    initialPageParam: 1,
    getNextPageParam: (lastPage) => {
      return lastPage.nextPage
    }
  })

  function handleScroll(event: UIEvent<HTMLElement>) {
    const { scrollTop, clientHeight, scrollHeight } = event.currentTarget

    if (scrollTop + clientHeight >= scrollHeight) {
      fetchNextPage()
    }
  };


  return (
    <main className="h-screen w-screen bg-zinc-950 flex flex-col gap-6 p-6 items-center text-white overflow-auto" onScroll={handleScroll}>
      {isLoading ? 'Loading...' : (
        <>
          {data?.pages.map((group, i) => (
            <div className="flex flex-col gap-6" key={i}>
              {group.data.map(({ id, urls }) => (
                <img className="aspect-square rounded-md h-[550px] object-cover" src={urls.regular} key={id} />
              ))}
            </div>
          ))}
          <div>
            <button
              onClick={() => fetchNextPage()}
              disabled={!hasNextPage || isFetchingNextPage}
            >
              {isFetchingNextPage
                ? 'Loading more...'
                : hasNextPage
                  ? 'Load More'
                  : 'Nothing more to load'}
          </button>
          </div>
          <div>{isFetching && !isFetchingNextPage ? 'Fetching...' : null}</div>
        </>
      )}
    </main>
  )
}

Merci !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn