Home > Web Front-end > JS Tutorial > body text

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

Mary-Kate Olsen
Release: 2024-11-10 10:01:02
Original
578 people have browsed it

Here's your post translated into English:


In this post, I’ll teach you how to implement infinite scrolling using TanStack Query, specifically with Infinity Queries. We’ll create a photo feed with Vite and set up infinite scrolling. To start, open your terminal and run the following command to clone a project with basic configurations:

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

cd photos-feed
npm i
Copy after login

All set! Now, let's implement the infinite scroll functionality using the TanStack Query library. Install it with the command below:

npm i @tanstack/react-query
npm i axios
Copy after login

In the App.tsx file, you'll see that your code looks like this:

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

First, we’ll replace useEffect with useInfiniteQuery, the hook responsible for managing our infinite requests. We must provide it with two properties: queryKey and queryFn, as follows:

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

Explanation of each parameter:

  • queryFn: The function responsible for returning our request data; it receives the current page as a parameter.
  • queryKey: Serves as an identifier for your request, also acting as a dependency array. Every time a variable you pass within it changes, useInfiniteQuery automatically refetches.
  • initialPageParam: The initial default value.
  • getNextPageParam: Receives everything your queryFn function returns and must return the next page number to be requested.

We’ll need to modify the fetchPhotos function:

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
  }
} 
Copy after login

The useInfiniteQuery hook returns the data in pages, so our rendering will change slightly:

<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>
Copy after login

Now, each time the user reaches the end of the scroll and clicks the ‘Load More’ button, the data will be automatically appended.

To fetch the next page whenever the user reaches the end of the scroll without needing to click the button, just add the following function:

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

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

And add the onScroll event in the div that wraps your list, calling the function there. Done! Now, every time the user scrolls to the end, new data will automatically load.

In the end, your code should look like this:

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>
  )
}
Copy after login

Thank you!

The above is the detailed content of How to use Infinity Queries (TanStack Query) to do infinite scrolling. For more information, please follow other related articles on the PHP Chinese website!

source:dev.to
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template