React Query and Pagination: The Ultimate Duo for Efficient Data Management

Written on 2023-05-04 by Adam Drake - 4 min read

Image of React Query and Pagination: The Ultimate Duo for Efficient Data Management

One common feature of dynamic websites is the display of a list of data generated from an underlying database. Typically, this list of data consists of an array of objects, each containing specific attributes that correspond to database fields. These dynamic lists enable websites to present real-time, curated content relevant to users, creating a highly engaging environment that caters to users' preferences and needs. Consequently, understanding the rendering process for these lists quickly becomes an essential skill in the web development field, as the expertise allows developers to create adaptable and personalized user experiences, as well as design websites that are efficient in both loading and managing data.

However, as this list grows you might not want to render the whole list on the screen. There are many disadvantages to this such as:

  1. Slow loading times: Showing a lot of data without pagination can greatly increase the loading time of a webpage, leading to a frustrating user experience.
  2. Difficult to navigate: When there is a large amount of data displayed, users might have trouble scrolling through the content and finding specific pieces of information.
  3. Higher server load: Serving large amounts of data on a single page can put a significant amount of strain on the server, impacting its performance, and potentially leading to crashes or extended loading times.
  4. Wasted resources: Loading all data at once can waste bandwidth and other resources, especially when users are only interested in specific data points or subsets.
If you haven't heard of react-query then I strongly suggest you check out their documentation and examples.

Therefore there are a number of options open to you as a developer to resolve this. One such option is Pagination (is it pronounced page-ignation OR padge-ination?! - Who knows...). This blog post will show you a simple pagination implementation using react-query/Tan stack query. If you haven't heard of react-query then I strongly suggest you check out their documentation and examples. It's very thorough and has many simple clear examples. It is a great library for dealing with fetching data and will generally improve all aspects of your life, even outside of development!

Pagination Example with React Query

Below is a very simple example of pagination using react-query:

function Projects() {
  const [page, setPage] = React.useState(0)

  const fetchProjects = (page = 0) => fetch('/api/projects?page=' + page).then((res) => res.json())

  const {
    isLoading,
    isError,
    error,
    data,
    isFetching,
    isPreviousData,
  } = useQuery({
    queryKey: ['projects', page],
    queryFn: () => fetchProjects(page),
    keepPreviousData : true
  })

  return (
    <div>
      {isLoading ? (
        <div>Loading...</div>
      ) : isError ? (
        <div>Error: {error.message}</div>
      ) : (
        <div>
          {data.projects.map(project => (
            <p key={project.id}>{project.name}</p>
          ))}
        </div>
      )}
      <span>Current Page: {page + 1}</span>
      <button
        onClick={() => setPage(old => Math.max(old - 1, 0))}
        disabled={page === 0}
      >
        Previous Page
      </button>{' '}
      <button
        onClick={() => {
          if (!isPreviousData && data.hasMore) {
            setPage(old => old + 1)
          }
        }}
        disabled={isPreviousData || !data?.hasMore}
      >
        Next Page
      </button>
      {isFetching ? <span> Loading...</span> : null}{' '}
    </div>
  )
}

There is an assumption here that the api you are working with is setup to receive a `page` query parameter so it knows which page of projects to return from the database.

This example is using `useState` to control the current `page` number:

const [page, setPage] = React.useState(0)

Then there are some buttons which navigate between the current page results and the next/previous depending on which page you are on. Clicking on these buttons will update the state object and this triggers react-query to either retrieve the data from the api or cache (depending on whether it's already been called).

There is an assumption here that the api you are working with is setup to receive a `page` query parameter so it knows which page of projects to return from the database.

Couple interesting things

keepPreviousData: true

This is used in the `useQuery` hook. This means the data from the last successful fetch is available while new data is being requested, even though the query key has changed. When the new data arrives, the previous data is seamlessly swapped to show the new data. Wow!

`isPreviousData` is made available to know what data the query is currently providing you.

Conclusion

Whilst this may not be the most sophisticated pagination example in the world, it is a good place to get started and provides many resolutions to the issues detailed at the beginning of this post. It also depends on the api you are working with and how much information that gives you. If you can get the number of objects in the first request then you can start getting fancy with your pagination so users can navigate to specific pages directly. It would just be an extension of the solution provided above.

Loading...

Adam Drake AI Selfie

Written by Adam Drake

Adam Drake is a Frontend React Developer who is very passionate about the quality of the web. He lives with his wife and three children in Prague in the Czech Republic.

Adam Drakes Site © 2024