Avoid overlapping fetches in infinite queries
There is one ongoing fetch for an infinite query cache entry. If you call fetchNextPage while a background refetch is running, you can overwrite data. To prevent this, disable the button or check !query.isFetching before loading more.
Use pagination pattern for single-page-at-a-time UI
If your UI shows one page at a time, a normal query with a page in the key can be a better fit than infinite queries. This pattern uses createQueryController, placeholderData: keepPreviousData, prefetching, and mutations.
Infinite queries load more data into one cache entry
Infinite queries are for lists that load more data into one cache entry. Use createInfiniteQueryController in Lit.
initialPageParam is required for infinite queries
initialPageParam is a required parameter for infinite queries. It specifies the initial page parameter value to pass to the query function for the first page.
getNextPageParam determines if another page exists
getNextPageParam is a function that decides whether another page exists and what value should be passed as pageParam to the next query function call. Returning undefined or null means there is no next page.
Infinite query result structure
An infinite query result contains: data.pages (fetched pages), data.pageParams (page parameters used for those pages), fetchNextPage and fetchPreviousPage functions, hasNextPage and hasPreviousPage booleans, and isFetchingNextPage and isFetchingPreviousPage booleans.
Infinite query property order for type inference
For useInfiniteQuery, useSuspenseInfiniteQuery, and infiniteQueryOptions, the property order matters for type inference. The correct order is: queryFn, getPreviousPageParam, getNextPageParam. All other properties are insensitive to order.
ESLint rule for infinite query property order
The @tanstack/query/infinite-query-property-order ESLint rule ensures correct property order in useInfiniteQuery, useSuspenseInfiniteQuery, and infiniteQueryOptions calls. The rule is recommended and fixable.
Correct infinite query property order example
Example of correct property order in useInfiniteQuery: queryKey, queryFn, initialPageParam, getPreviousPageParam, getNextPageParam, maxPages. The three order-sensitive properties (queryFn, getPreviousPageParam, getNextPageParam) must appear in this exact sequence.
fetchNextPage function behavior
The fetchNextPage function is used to trigger loading of the next page of data. It should be disabled when hasNextPage is false or when isFetching is true to prevent invalid requests or duplicate fetches.
useInfiniteQuery hook basic usage in Preact
The useInfiniteQuery hook from @tanstack/preact-query is used to fetch paginated data. The queryFn receives a pageParam parameter that is used to request the specific page. The hook returns an object with properties including data (containing pages array), error, fetchNextPage (function to load more data), hasNextPage (boolean indicating if more pages exist), isFetching (boolean for any fetching state), isFetchingNextPage (boolean for specifically the next page fetch), and status (pending, error, or success).
initialPageParam in useInfiniteQuery
The initialPageParam option is a required parameter in useInfiniteQuery that specifies the value passed to queryFn for the first page request. In the example, initialPageParam is set to 0, which is passed as pageParam to the fetchProjects function for the initial fetch.
getNextPageParam function in infinite queries
The getNextPageParam option is a function that receives the lastPage and pages array as parameters and returns the value to be used as pageParam for the next fetch. It determines whether there are more pages and what cursor or offset value should be used. In the example, it extracts lastPage.nextCursor to determine the cursor for the next request.
data.pages structure in infinite queries
In infinite queries, the data object contains a pages array where each element represents the response from a single page request. You can iterate through data.pages to render results from all fetched pages.
Infinite query example with cursor-based pagination
Example showing useInfiniteQuery with cursor-based pagination:
```tsx
import { useInfiniteQuery } from '@tanstack/preact-query'
function Projects() {
const fetchProjects = async ({ pageParam }) => {
const res = await fetch('/api/projects?cursor=' + pageParam)
return res.json()
}
const {
data,
error,
fetchNextPage,
hasNextPage,
isFetching,
isFetchingNextPage,
status,
} = useInfiniteQuery({
queryKey: ['projects'],
queryFn: fetchProjects,
initialPageParam: 0,
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
})
return status === 'pending' ? (
<p>Loading...</p>
) : status === 'error' ? (
<p>Error: {error.message}</p>
) : (
<>
{data.pages.map((group, i) => (
<div key={i}>
{group.data.map((project) => (
<p key={project.id}>{project.name}</p>
))}
</div>
))}
<div>
<button
onClick={() => fetchNextPage()}
disabled={!hasNextPage || isFetching}
>
{isFetchingNextPage
? 'Loading more...'
: hasNextPage
? 'Load More'
: 'Nothing more to load'}
</button>
</div>
<div>{isFetching && !isFetchingNextPage ? 'Fetching...' : null}</div>
</>
)
}
```
This example demonstrates cursor-based pagination where the API returns a nextCursor in the response that is used for subsequent requests.