Execution contract
- Use when
- Use for a list that appends pages and receives the next cursor or explicit offset from the server contract.
- Avoid when
- Prefer URL page state and a regular Query when pagination needs shareable page numbers or random access.
- Preconditions
- Define initialPageParam, final-page signal, stable query key, page response shape, and whether maxPages or bidirectional paging is required.
- Verification
- Record sequential pageParams and test final-page, retry, filter changes, and repeated clicks; pages and pageParams must always correspond.
- Failure mode
- Duplicate pages usually come from guessed cursors, a stale getNextPageParam result, or concurrent fetchNextPage calls; inspect network records and the last-page response.
- Security
- Cursors are tamperable external input; the server must validate scope, ordering, and user permissions rather than treating a cursor as authorization.
Input contract
Define the first pageParam, response nextCursor, final-page signal, and list filters. Filters belong in queryKey and cursors belong in pageParam. For offset APIs, derive the next value explicitly from lastPageParam rather than component-local page state.
Minimal implementation
initialPageParam and getNextPageParam are required v5 contracts. Return undefined to end the list and propagate AbortSignal to stop obsolete work. When maxPages is positive, bidirectional pagination also requires getPreviousPageParam.
import { infiniteQueryOptions } from '@tanstack/react-query'
export const issueFeedOptions = infiniteQueryOptions({
queryKey: ['issues', 'feed'] as const,
initialPageParam: null as string | null,
queryFn: ({ pageParam, signal }) => fetchIssuePage(pageParam, signal),
getNextPageParam: (page) => page.nextCursor ?? undefined,
maxPages: 5,
})Cache and interaction checks
Flatten data.pages for rendering but preserve `{ pages, pageParams }` in cache writes. Gate load-more with both hasNextPage and isFetchingNextPage; test final-page, retry, filter changes, rapid repeated triggers, and maxPages eviction direction.