Skip to main content

useInfiniteQuery

For infinite query hooks such as useInfiniteQuery and useSuspenseInfiniteQuery, queryData should be a function that maps a context object containing pageParam to the actual query data.

import { tsr } from './tsr';

const PAGE_SIZE = 5;

export const Posts = () => {
const { data, isLoading, isError, fetchNextPage, hasNextPage } = tsr.getPosts.useInfiniteQuery({
queryKey: ['posts'],
queryData: ({ pageParam }) => ({
query: {
skip: pageParam.skip,
take: pageParam.take,
},
}),
initialPageParam: { skip: 0, take: PAGE_SIZE },
getNextPageParam: (lastPage, allPages) => {
return lastPage.body.posts.length >= PAGE_SIZE
? { take: PAGE_SIZE, skip: allPages.length * PAGE_SIZE }
: undefined;
},
});

if (isLoading) {
return <div>Loading...</div>;
}

if (isError) {
return <div>Error</div>;
}

const posts = data.pages.flatMap((page) =>
page.status === 200 ? page.body.posts : [],
);

return (
<div>
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
<button onClick={fetchNextPage}>Load more</button>
</div>
);
};

See the official useInfiniteQuery() docs for more information.

QueryClient Methods

You can also use fetchInfiniteQuery and prefetchInfiniteQuery on the ts-rest extended QueryClient.

These will take the same arguments as fetchQuery, but need to specify an initialPageParam in order to correctly put the data in the cache with its corresponding pageParam.

import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query';
import { tsr } from './tsr';

export default async function Page() {
const tsrQueryClient = tsr.initQueryClient(new QueryClient());

const initialPageParam = { skip: 0, take: 10 };
await tsrQueryClient.getPosts.prefetchInfiniteQuery({
queryKey: ['posts'],
queryData: {
query: initialPageParam,
},
initialPageParam,
});

return (
<main>
<HydrationBoundary state={dehydrate(tsrQueryClient)}>
<Posts />
</HydrationBoundary>
</main>
);
}