SoulCache

Infinite Query

Learn about SoulCache's infinite query for paginated data

Infinite Query

Infinite queries handle paginated data fetching with automatic cursor management.

Import

import { InfiniteQuery } from '@soulcache/core';

Constructor

new InfiniteQuery<TData, TPageParam>(options: InfiniteQueryOptions<TData, TPageParam>)

Types

InfiniteQueryOptions<TData, TPageParam>

interface InfiniteQueryOptions<TData, TPageParam> {
  readonly queryKey: QueryKey;
  readonly queryFn: (context: { pageParam: TPageParam; signal?: AbortSignal }) => Promise<TData>;
  readonly initialPageParam?: TPageParam;       // default: 0
  readonly getNextPageParam: (
    lastPage: TData, allPages: TData[],
    lastPageParam: unknown, allPageParams: unknown[],
  ) => TPageParam | undefined;
  readonly getPreviousPageParam?: (
    firstPage: TData, allPages: TData[],
    firstPageParam: unknown, allPageParams: unknown[],
  ) => TPageParam | undefined;
  readonly enabled?: boolean;
  readonly staleTime?: number;
  readonly gcTime?: number;
  readonly maxPages?: number;                   // default: Infinity
}

InfiniteQueryState<TData>

interface InfiniteQueryState<TData> {
  readonly pages: InfiniteQueryPage<TData>[];
  readonly pageParams: unknown[];
  readonly hasNextPage: boolean;
  readonly hasPreviousPage: boolean;
  readonly isFetchingNextPage: boolean;
  readonly isFetchingPreviousPage: boolean;
  readonly error: Error | null;
}

InfiniteQueryPage<TData>

interface InfiniteQueryPage<TData> {
  readonly data: TData;
  readonly pageParam: unknown;
  readonly pageIndex: number;
}

Properties

PropertyTypeDescription
idstringUnique query ID
queryKeyreadonly unknown[]Query cache key
dataTData[]Flat array of all page data
hasNextPagebooleanWhether next page is available
hasPreviousPagebooleanWhether previous page is available
isFetchingNextPagebooleanWhether next page is fetching
isFetchingPreviousPagebooleanWhether previous page is fetching
pageCountnumberNumber of loaded pages
isDestroyedbooleanWhether query is destroyed

Methods

fetch()

Fetch all pages.

fetch(): Promise<void>

fetchNextPage()

Fetch the next page. Returns true if a new page was fetched.

fetchNextPage(): Promise<boolean>

fetchPreviousPage()

Fetch the previous page. Returns true if a new page was fetched.

fetchPreviousPage(): Promise<boolean>

subscribe(listener)

Subscribe to state changes.

subscribe(listener: () => void): () => void

cancel()

Cancel any in-flight fetch.

cancel(): void

reset()

Reset to initial state.

reset(): void

destroy()

Destroy the query and cleanup resources.

destroy(): void

Usage

import { InfiniteQuery } from '@soulcache/core';
 
const query = new InfiniteQuery({
  queryKey: ['posts'],
  queryFn: async ({ pageParam }) => {
    const response = await fetch(`/api/posts?page=${pageParam}`);
    return response.json();
  },
  getNextPageParam: (lastPage) => lastPage.nextCursor,
  getPreviousPageParam: (firstPage) => firstPage.prevCursor,
});
 
// Fetch first page
await query.fetch();
 
// Fetch next page
const hasNext = await query.fetchNextPage();
 
// Subscribe to updates
const unsubscribe = query.subscribe(() => {
  console.log(query.data);
  console.log(query.hasNextPage);
});

Features

Automatic Cursor Management

Cursor tracking is handled automatically between pages

Bidirectional Pagination

Support for both forward and backward pagination

Background Refetching

Pages are refreshed in the background to stay current

Max Pages Limit

Control memory usage by limiting number of kept pages

Best Practices

Infinite Query Guidelines

  • Use stable cursors — Ensure consistent pagination across refetches
  • Handle loading states — Show feedback during page fetches
  • Implement error boundaries — Handle fetch failures gracefully
  • Limit pages — Use maxPages to control memory usage

On this page