Paginated & Infinite Queries
Nischal Dutt
Posted on October 2, 2022
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;
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
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
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
totrue
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;
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!
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
September 19, 2024