Skip to content

Infinite queries

createInfiniteQuery wraps TanStack Query’s InfiniteQueryObserver and exposes the same API as createQuery plus pagination-specific stores and events.

Basic usage

import { createInfiniteQuery } from '@effector-tanstack-query/core'
const postsQuery = createInfiniteQuery({
name: 'posts',
queryKey: ['posts'],
queryFn: ({ pageParam }) =>
fetch(`/api/posts?cursor=${pageParam}`).then((r) => r.json()),
getNextPageParam: (lastPage) => lastPage.nextCursor,
initialPageParam: 0,
})
postsQuery.mounted()
postsQuery.fetchNextPage() // load more

Stores and events

In addition to all QueryResult fields:

FieldTypeDescription
$dataStore<InfiniteData<T> | undefined>All pages + pageParams
$hasNextPageStore<boolean>More pages available forward
$hasPreviousPageStore<boolean>More pages available backward
$isFetchingNextPageStore<boolean>Next page is fetching
$isFetchingPreviousPageStore<boolean>Previous page is fetching
$isFetchNextPageErrorStore<boolean>Next page fetch failed
$isFetchPreviousPageErrorStore<boolean>Previous page fetch failed
fetchNextPageEventCallable<void>Fetch next page
fetchPreviousPageEventCallable<void>Fetch previous page
refreshEventCallable<void>Invalidate & refetch all pages

Bidirectional pagination

const chatQuery = createInfiniteQuery({
name: 'chat',
queryKey: ['messages'],
queryFn: ({ pageParam }) => fetchMessages(pageParam),
getNextPageParam: (lastPage) => lastPage.nextCursor,
getPreviousPageParam: (firstPage) => firstPage.prevCursor,
initialPageParam: 'latest',
})
chatQuery.fetchNextPage() // older
chatQuery.fetchPreviousPage() // newer

maxPages

Cap the number of retained pages — older pages are evicted as new ones load:

createInfiniteQuery({
name: 'feed',
// ...
maxPages: 10,
})

select on infinite data

select receives InfiniteData<TQueryFnData, TPageParam> and can return any shape:

const postsQuery = createInfiniteQuery({
name: 'posts',
queryKey: ['posts'],
queryFn: ({ pageParam }: { pageParam: number }) => fetchPage(pageParam),
getNextPageParam: (last) => last.nextCursor,
initialPageParam: 0,
// Flatten pages into a single array
select: (data) => data.pages.flatMap((page) => page.items),
})
postsQuery.$data // Store<Post[] | undefined>

Refetch behavior

refresh() (or queryClient.invalidateQueries) refetches every loaded page using getNextPageParam to recompute cursors from the freshly-fetched data. The original pageParams in the cache are replaced.

This is by design — pagination cursors often depend on server state and shouldn’t be assumed stable.

In React

See useInfiniteQuery and useSuspenseInfiniteQuery.