Paginated & Infinite Queries
Tags: javascript, webdev, beginners, react
Published: 2022-10-02 12:05:55

## 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:

```jsx
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;
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g1i9z3nbv799ie4nd5t8.gif)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qlkhb13epln7q2pcw1h6.gif)

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.

```jsx
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;
```

![infinite queries using useInfiniteQueries](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tbdva9414uxln2qn13bp.gif)


---

## 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](https://github.com/nischaldutt) [✨ Twitter](https://twitter.com/nischal_dutt) [💌 Email](mailto:nischaldutt01@gmail.com) [💡Linkedin](https://www.linkedin.com/in/nischal-dutt) 

Till then happy coding!