@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

ParameterTypeDefaultDescription
paramsVSQueryParamsdefaultParamsFilters and limit. Do not pass page — it is managed internally.

#Key return fields

FieldDescription
data.pagesArray of all fetched pages. Each has items and pagination.
fetchNextPage()Fetches the next page. No-op when hasNextPage is false.
hasNextPagefalse when the last page has been fetched.
isFetchingNextPagetrue while the next page is loading.
isLoadingtrue on the very first fetch.
isErrortrue 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>
  );
}