useActorSuspenseInfiniteQuery
useActorSuspenseInfiniteQuery is a React hook for fetching paginated data from canisters with Suspense support. It suspends the component until the first page is loaded.
Import
Section titled “Import”import { createActorHooks } from "@ic-reactor/react"
const { useActorSuspenseInfiniteQuery } = createActorHooks(backend)import { Suspense } from "react"
function ItemList() { const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useActorSuspenseInfiniteQuery({ functionName: "getItems", getArgs: (pageParam) => [{ offset: pageParam, limit: 10 }], initialPageParam: 0, getNextPageParam: (lastPage, allPages) => lastPage.items.length < 10 ? undefined : allPages.length * 10, })
// data.pages is ALWAYS defined - no undefined check needed return ( <div> {data.pages.map((page, i) => ( <div key={i}> {page.items.map((item) => ( <Item key={item.id} data={item} /> ))} </div> ))}
<button onClick={() => fetchNextPage()} disabled={!hasNextPage || isFetchingNextPage} > {isFetchingNextPage ? "Loading..." : hasNextPage ? "Load More" : "End"} </button> </div> )}
// Must be wrapped in Suspensefunction App() { return ( <Suspense fallback={<LoadingSkeleton />}> <ItemList /> </Suspense> )}Options
Section titled “Options”UseActorSuspenseInfiniteQueryParameters extends react-query’s UseSuspenseInfiniteQueryOptions, giving you access to all standard react-query options plus our custom actor options.
Same as useActorInfiniteQuery except:
Key Options
Section titled “Key Options”| Option | Type | Description |
|---|---|---|
functionName |
string |
The canister method to call |
getArgs |
function |
Returns args for each page |
initialPageParam |
TPageParam |
Initial page parameter |
getNextPageParam |
function |
Returns next page param |
getPreviousPageParam |
function |
Returns previous page param (optional) |
maxPages |
number |
Max pages to cache (optional) |
staleTime |
number |
Time before data is stale |
Return Value
Section titled “Return Value”Returns a TanStack Query suspense infinite result. Key difference from useActorInfiniteQuery:
| Property | Type | Description |
|---|---|---|
data |
InfiniteData<TData> |
Always defined (never undefined) |
data.pages |
TData[] |
Array of all pages (at least one) |
data.pageParams |
TPageParam[] |
Array of page parameters |
error |
never |
Errors are thrown, not returned |
status |
'success' |
Always success |
hasNextPage |
boolean |
More pages available |
hasPreviousPage |
boolean |
Previous pages available |
fetchNextPage |
function |
Fetch next page |
fetchPreviousPage |
function |
Fetch previous page |
isFetchingNextPage |
boolean |
Fetching next page |
isFetchingPreviousPage |
boolean |
Fetching previous page |
Examples
Section titled “Examples”Basic Usage
Section titled “Basic Usage”function ProductList() { const { data, fetchNextPage, hasNextPage } = useActorSuspenseInfiniteQuery({ functionName: "getProducts", getArgs: (page) => [{ page, perPage: 20 }], initialPageParam: 1, getNextPageParam: (lastPage, allPages, lastPageParam) => lastPage.hasMore ? lastPageParam + 1 : undefined, })
// data is guaranteed to have at least one page return ( <div> {data.pages .flatMap((page) => page.products) .map((product) => ( <ProductCard key={product.id} product={product} /> ))}
{hasNextPage && ( <button onClick={() => fetchNextPage()}>Load More</button> )} </div> )}
function App() { return ( <Suspense fallback={<ProductListSkeleton />}> <ProductList /> </Suspense> )}With Error Boundary
Section titled “With Error Boundary”import { ErrorBoundary } from "react-error-boundary"
function ErrorFallback({ error, resetErrorBoundary }) { return ( <div className="error"> <p>Failed to load items</p> <pre>{error.message}</pre> <button onClick={resetErrorBoundary}>Retry</button> </div> )}
function App() { return ( <ErrorBoundary FallbackComponent={ErrorFallback}> <Suspense fallback={<Loading />}> <ItemList /> </Suspense> </ErrorBoundary> )}Infinite Scroll with Suspense
Section titled “Infinite Scroll with Suspense”import { useInView } from "react-intersection-observer"import { useEffect, Suspense } from "react"
function InfiniteList() { const { ref, inView } = useInView()
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useActorSuspenseInfiniteQuery({ functionName: "getItems", getArgs: (offset) => [{ offset, limit: 20 }], initialPageParam: 0, getNextPageParam: (lastPage, allPages) => lastPage.items.length < 20 ? undefined : allPages.length * 20, })
useEffect(() => { if (inView && hasNextPage && !isFetchingNextPage) { fetchNextPage() } }, [inView, hasNextPage, isFetchingNextPage, fetchNextPage])
return ( <div> {data.pages .flatMap((page) => page.items) .map((item) => ( <ItemCard key={item.id} item={item} /> ))}
<div ref={ref}>{isFetchingNextPage && <LoadingSpinner />}</div> </div> )}
function App() { return ( <Suspense fallback={<ListSkeleton />}> <InfiniteList /> </Suspense> )}Flattened Data with Select
Section titled “Flattened Data with Select”const { data: items } = useActorSuspenseInfiniteQuery({ functionName: "getItems", getArgs: (offset) => [{ offset, limit: 20 }], initialPageParam: 0, getNextPageParam: (lastPage, allPages) => lastPage.items.length < 20 ? undefined : allPages.length * 20, select: (data) => data.pages.flatMap((page) => page.items),})
// items is a flat array of all items across all pagesreturn ( <ul> {items.map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul>)When to Use
Section titled “When to Use”✅ Use Suspense Infinite Query when:
- You always need paginated data (no conditional fetching)
- You want automatic loading states at the boundary level
- You’re building a feed or list that requires pagination
❌ Use regular useActorInfiniteQuery when:
- You need conditional fetching (
enabledoption) - You want per-component loading states
- You need access to
isPendingstate
See Also
Section titled “See Also”- useActorInfiniteQuery — Regular infinite query
- useActorSuspenseQuery — Single suspense query
- Queries Guide — In-depth query patterns
- createActorHooks — Creating hooks