The InfiniteQueryObserver extends QueryObserver to provide additional functionality for infinite queries (pagination). It powers hooks like useInfiniteQuery.
Constructor
Creates a new InfiniteQueryObserver instance.
const observer = new InfiniteQueryObserver < TQueryFnData , TError , TData , TQueryKey , TPageParam >(
client : QueryClient ,
options : InfiniteQueryObserverOptions < TQueryFnData , TError , TData , TQueryKey , TPageParam >
)
The QueryClient instance to use.
options
InfiniteQueryObserverOptions
required
Options for the infinite query observer. A unique key for the query.
The function that fetches pages. Receives a context object with pageParam.
The default page param to use when fetching the first page.
getNextPageParam
(lastPage: TQueryFnData, allPages: TQueryFnData[], lastPageParam: TPageParam, allPageParams: TPageParam[]) => TPageParam | undefined
required
Function to get the next page param. Return undefined to indicate no more pages.
getPreviousPageParam
(firstPage: TQueryFnData, allPages: TQueryFnData[], firstPageParam: TPageParam, allPageParams: TPageParam[]) => TPageParam | undefined
Function to get the previous page param. Return undefined to indicate no more pages.
Maximum number of pages to keep in the cache.
Example
import { InfiniteQueryObserver } from '@tanstack/query-core'
const observer = new InfiniteQueryObserver ( queryClient , {
queryKey: [ 'projects' ],
queryFn : async ({ pageParam }) => {
const response = await fetch ( `/api/projects?cursor= ${ pageParam } ` )
return response . json ()
},
initialPageParam: 0 ,
getNextPageParam : ( lastPage , allPages , lastPageParam ) => lastPage . nextCursor ,
getPreviousPageParam : ( firstPage , allPages , firstPageParam ) => firstPage . prevCursor ,
})
Methods
InfiniteQueryObserver inherits all methods from QueryObserver and adds the following:
fetchNextPage
Fetches the next page of data.
fetchNextPage (
options ?: FetchNextPageOptions
): Promise < InfiniteQueryObserverResult < TData , TError >>
Options for fetching the next page. Whether to cancel any ongoing refetch. Default is true.
Promise<InfiniteQueryObserverResult>
Returns a promise that resolves with the infinite query result.
Example
const result = await observer . fetchNextPage ()
console . log ( 'Has next page:' , result . hasNextPage )
console . log ( 'All pages:' , result . data . pages )
fetchPreviousPage
Fetches the previous page of data.
fetchPreviousPage (
options ?: FetchPreviousPageOptions
): Promise < InfiniteQueryObserverResult < TData , TError >>
Options for fetching the previous page. Whether to cancel any ongoing refetch. Default is true.
Promise<InfiniteQueryObserverResult>
Returns a promise that resolves with the infinite query result.
Example
const result = await observer . fetchPreviousPage ()
console . log ( 'Has previous page:' , result . hasPreviousPage )
subscribe
Subscribes to the observer. Same as QueryObserver but with InfiniteQueryObserverResult.
subscribe (
listener : ( result : InfiniteQueryObserverResult < TData , TError >) => void
): () => void
listener
(result: InfiniteQueryObserverResult<TData, TError>) => void
required
Function called when the query result changes.
Returns an unsubscribe function.
Example
const unsubscribe = observer . subscribe (( result ) => {
console . log ( 'Pages:' , result . data ?. pages )
console . log ( 'Page params:' , result . data ?. pageParams )
console . log ( 'Has next page:' , result . hasNextPage )
console . log ( 'Has previous page:' , result . hasPreviousPage )
console . log ( 'Is fetching next page:' , result . isFetchingNextPage )
})
unsubscribe ()
getCurrentResult
Returns the current infinite query result.
getCurrentResult (): InfiniteQueryObserverResult < TData , TError >
InfiniteQueryObserverResult
InfiniteQueryObserverResult
Returns the current infinite query result. data
InfiniteData<TData, TPageParam> | undefined
The infinite data structure containing pages and pageParams. Array of pages that have been fetched.
Array of page params corresponding to each page.
The error object if the query failed.
status
'pending' | 'error' | 'success'
The status of the query.
True if there is a next page to fetch.
True if there is a previous page to fetch.
True if currently fetching the next page.
True if currently fetching the previous page.
True if there was an error fetching the next page.
True if there was an error fetching the previous page.
fetchNextPage
(options?: FetchNextPageOptions) => Promise<InfiniteQueryObserverResult>
Function to fetch the next page.
fetchPreviousPage
(options?: FetchPreviousPageOptions) => Promise<InfiniteQueryObserverResult>
Function to fetch the previous page.
setOptions
Updates the observer options. Automatically sets the infinite query behavior.
setOptions (
options : InfiniteQueryObserverOptions < TQueryFnData , TError , TData , TQueryKey , TPageParam >
): void
options
InfiniteQueryObserverOptions
required
New options for the observer.
getOptimisticResult
Returns an optimistic infinite query result.
getOptimisticResult (
options : DefaultedInfiniteQueryObserverOptions < TQueryFnData , TError , TData , TQueryKey , TPageParam >
): InfiniteQueryObserverResult < TData , TError >
InfiniteData Structure
The data returned by an infinite query has a special structure:
interface InfiniteData < TData , TPageParam > {
pages : TData []
pageParams : TPageParam []
}
Example
const result = observer . getCurrentResult ()
if ( result . data ) {
// Access all pages
result . data . pages . forEach (( page , index ) => {
console . log ( `Page ${ index } :` , page )
console . log ( `Page param:` , result . data . pageParams [ index ])
})
// Flatten all items from all pages
const allItems = result . data . pages . flatMap ( page => page . items )
}
Usage Example
Here’s a complete example:
import { QueryClient , InfiniteQueryObserver } from '@tanstack/query-core'
const queryClient = new QueryClient ()
const observer = new InfiniteQueryObserver ( queryClient , {
queryKey: [ 'projects' ],
queryFn : async ({ pageParam }) => {
const response = await fetch (
`/api/projects?cursor= ${ pageParam } &limit=10`
)
return response . json ()
},
initialPageParam: 0 ,
getNextPageParam : ( lastPage , allPages , lastPageParam ) => {
// Return undefined if no more pages
return lastPage . nextCursor ?? undefined
},
getPreviousPageParam : ( firstPage , allPages , firstPageParam ) => {
return firstPage . prevCursor ?? undefined
},
})
const unsubscribe = observer . subscribe (( result ) => {
if ( result . isLoading ) {
console . log ( 'Loading first page...' )
} else if ( result . isError ) {
console . error ( 'Error:' , result . error )
} else if ( result . isSuccess ) {
console . log ( 'Total pages loaded:' , result . data . pages . length )
if ( result . hasNextPage && ! result . isFetchingNextPage ) {
// Automatically fetch next page
observer . fetchNextPage ()
}
}
if ( result . isFetchingNextPage ) {
console . log ( 'Loading more...' )
}
})
// Clean up
unsubscribe ()
observer . destroy ()
Differences from QueryObserver
Data Structure : Returns InfiniteData<TData, TPageParam> instead of TData
Additional Methods : fetchNextPage() and fetchPreviousPage()
Additional Result Properties : hasNextPage, hasPreviousPage, isFetchingNextPage, etc.
Required Options : Requires initialPageParam, getNextPageParam
Automatic Behavior : Automatically applies infinite query behavior
Page Management
You can control the number of pages kept in memory using the maxPages option:
const observer = new InfiniteQueryObserver ( queryClient , {
queryKey: [ 'projects' ],
queryFn: fetchProjects ,
initialPageParam: 0 ,
getNextPageParam : ( lastPage ) => lastPage . nextCursor ,
maxPages: 3 , // Only keep 3 pages in memory
})
When maxPages is set, the oldest pages will be removed as new pages are fetched.