Paginated & Infinite Queries

nischal_dutt

Nischal Dutt

Posted on October 2, 2022

Paginated & Infinite Queries

Paginated/Lagged Queries

Rendering paginated data is a very common UI pattern and in React Query, it "just works" by including the page information in the query key.

To perform paginated queries consider we have a list of colors, we can perform pagination as follows:

import React from "react";
import { useQuery } from "@tanstack/react-query";

const fetchColors = ({ queryKey }) => {
  const pageNumber = queryKey[1];
  return fetch(
    `http://localhost:4000/colors?_limit=2&_page=${pageNumber}`
  ).then((response) => response.json());
};

const Colors = () => {
  const [currPageNum, setCurrPageNum] = React.useState(1);

  const { data: colors, isFetching } = useQuery(
    ["colors", currPageNum],
    fetchColors,
    {
      keepPreviousData: true,
    }
  );

  return (
    <div>
      {colors?.map((color) => (
        <div key={color.id}>{color.name}</div>
      ))}

      <button
        onClick={() => setCurrPageNum((currPageNum) => currPageNum - 1)}
        disabled={currPageNum === 1}
      >
        previous
      </button>
      <button
        onClick={() => setCurrPageNum((currPageNum) => currPageNum + 1)}
        disabled={currPageNum === 5}
      >
        next
      </button>
      <div>{isFetching ? "loading..." : null}</div>
    </div>
  );
};

export default Colors;
Enter fullscreen mode Exit fullscreen mode

One point to note here is that we’ve used keepPreviousData config to true. Let us see the significance of using it,

If we don’t use keepPreviousData

not using keepPreviousData option

The UI jumps in and out of the success and loading states because each new page is treated like a brand new query.

If we use keepPreviousData

using keepPreviousData option

This time even though the data is being fetched each time, the loading state is not shown as the previous data is used on display while the background fetch is being performed and swapped once new data is available.

According to React Query docs,

By setting keepPreviousData to true we get a few new things:

  • 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.
  • isPreviousData is made available to know what data the query is currently providing you.

Infinite Queries

Infinite queries can be a great UX feature if it is performed efficiently. React Query supports a useful version of useQuery called useInfiniteQuery for querying such kind of lists.

Consider we have a list of games, and we want users to show 2 games at a time after which the user should click the fetch more button at the bottom to view the next 2 games.
Here's how we’ll perform this using the mighty useInfiniteQueries hook.

import React from "react";
import { useInfiniteQuery } from "@tanstack/react-query";

const fetchGames = async ({ pageParam = 1 }) => {
  return fetch(`http://localhost:4000/games?_limit=2&_page=${pageParam}`).then(
    (response) => response.json()
  );
};

const TopGames = () => {
  const {
    isLoading,
    data,
    isError,
    error,
    hasNextPage,
    isFetching,
    fetchNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery(["games"], fetchGames, {
    getNextPageParam: (_lastPage, pages) => {
      return pages.length < 5 ? pages.length + 1 : undefined;
    },
  });

  if (isLoading) {
    return <h4>loading</h4>;
  }

  if (isError) {
    return <h4>{error.message}</h4>;
  }

  return (
    <div>
      {data?.pages.map((group, index) => {
        return (
          <div key={index}>
            {group.map((game) => {
              return <h3 key={game.id}>{game.name}</h3>;
            })}
          </div>
        );
      })}

      <button disabled={!hasNextPage} onClick={fetchNextPage}>
        load more
      </button>
      <div>{isFetching && isFetchingNextPage ? "loading..." : null}</div>
    </div>
  );
};

export default TopGames;
Enter fullscreen mode Exit fullscreen mode

infinite queries using useInfiniteQueries


Thank you for reading!

Now that we have covered common use cases for fetching the information that developers face, let us learn about how to perform mutations i.e. CRUD operations with React Query.
Feel free to reach out to me! 😊

💻 Github ✨ Twitter 💌 Email 💡Linkedin

Till then happy coding!

💖 💪 🙅 🚩
nischal_dutt
Nischal Dutt

Posted on October 2, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related