@void-snippets/react
useInfinite
Infinite scroll pagination with fetchNextPage and hasNextPage.
#What it does
Loads a paginated list where each new page is fetched on demand — "Load more" or infinite scroll. Internally uses TanStack Query's useInfiniteQuery.
#Signature
typescript
contactHooks.useInfinite(params?: VSQueryParams): UseInfiniteQueryResult<VSListResult<Contact.Base>, Error>#Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
params | VSQueryParams | defaultParams | Filters and limit. Do not pass page — it is managed internally. |
#Key return fields
| Field | Description |
|---|---|
data.pages | Array of all fetched pages. Each has items and pagination. |
fetchNextPage() | Fetches the next page. No-op when hasNextPage is false. |
hasNextPage | false when the last page has been fetched. |
isFetchingNextPage | true while the next page is loading. |
isLoading | true on the very first fetch. |
isError | true when a fetch failed. |
#Example — "Load more" button
tsx
function ContactsFeed() {
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } =
contactHooks.useInfinite({ limit: 15 });
// Flatten all pages into one array for rendering
const contacts = data?.pages.flatMap(page => page.items) ?? [];
if (isLoading) return <Spinner />;
return (
<div>
{contacts.map(contact => (
<ContactCard key={contact._id} contact={contact} />
))}
{hasNextPage && (
<Button
onClick={() => fetchNextPage()}
loading={isFetchingNextPage}
disabled={isFetchingNextPage}
>
{isFetchingNextPage ? 'Loading…' : 'Load more'}
</Button>
)}
{!hasNextPage && contacts.length > 0 && (
<p>All {contacts.length} contacts loaded.</p>
)}
</div>
);
}