šŸŽ Checkout my Learn React by Making a Game course and get 1 month Free on Skillshare!

NextJs 13 pagination with useInfiniteQuery()

Hi friends! Let's build a simple NextJs 13 example that displays some paginated data from the jsonplaceholder.typicode.com API using the useInfiniteQuery() hook.

The example app will have a Load more button that fetches new data and changes its state based on the status of the request.

If you want to skip ahead you can see the running example here and the full code on GitHub.

So, let's get to work!

Setting up the QueryClientProvider

First of all, we will use client hooks on our NextJs page so be sure to mark it with the use client directive.

To use the useInfiniteQuery() hook we will first need to set up some context:

'use client'

import { useInfiniteQuery, QueryClient, QueryClientProvider } from "@tanstack/react-query"

const queryClient = new QueryClient();

const MyComponent = ()=> {
  // šŸ¦„ the magic of useInfiniteQuery() goes here
}

export default function Home() {
  return (
    <QueryClientProvider client={queryClient}>
        <MyComponent />
    </QueryClientProvider>
  )
}

Not setting up the QueryClientProvider will throw the error No QueryClient set, use QueryClientProvider to set one.

Loading up the first page of data with useInfiniteQuery()

Having the setup ready, let's load the initial page of data.

Will first define the actual data fetching function:

const fetchData = async (page) => {
  const response = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=27&_page=' + page)
  const posts = (await response.json())
  return posts;
}

The typicode API will return a max of 100 posts. For the sake of the example, we are fetching 27 items per page, and the page number is controlled by the page variable.

Now that we have the data-fetching function ready we can pass it to the useInfiniteQuery() hook and display the initial data:

const MyComponent = ()=> {
  const {data, fetchNextPage, isFetchingNextPage} = useInfiniteQuery(
    ['query'], 
    async ({pageParam = 1}) => {
      const response = await fetchData(pageParam)
      return response
    }, 
    {
      getNextPageParam: (_, pages) => {
        return pages.length + 1
      }
    }
  )
  return <>
    <h1>šŸ“– Post list</h1>
    <ol>
      {data?.pages.map((page, i)=> (
        <span key={i}>
          {page.map(p => <li key={p.id}>{p.title}</li>)}
        </span>
      ))}
    </ol>
  </>
}

Adding the Load More button

The final step is to add a Load More button that will trigger the loading of the next page of data:

const loadMoreBtnText = ()=> {
    if (isFetchingNextPage) {
      return 'ā³ Fetching posts'
    }
    let lastPage = data?.pages[data?.pages.length-1]
    if(!lastPage?.length) {
      return 'Nothing left to load'
    }
    return 'Load more'
}

// ...

 <button 
      onClick={() => fetchNextPage()}
      disabled={isFetchingNextPage}>
        {loadMoreBtnText()}
</button>

The isFetchingNextPage parameter will disable the button when the actual fetching is in progress.

As said before, given that the API returns a maximum of 100 posts, we will press the Load More button 3 times until the text is changed to Nothing left to load.

We can also use a hidden load more button, to build an infinite scroll effect.

And this is it! You can check out the running example, and the full code of the app here.

šŸ“– 50 Javascript, React and NextJs Projects

Learn by doing with this FREE ebook! Not sure what to build? Dive in with 50 projects with project briefs and wireframes! Choose from 8 project categories and get started right away.

šŸ“– 50 Javascript, React and NextJs Projects

Learn by doing with this FREE ebook! Not sure what to build? Dive in with 50 projects with project briefs and wireframes! Choose from 8 project categories and get started right away.


Leave a Reply

Your email address will not be published. Required fields are marked *