Skip to Content
API ReferenceHooksuseNexusInfiniteQuery

useNexusInfiniteQuery

useNexusInfiniteQuery is a client-side hook for building “infinite scroll” or “load more” UIs. It manages page parameters, fetching, and state aggregation.

Import

import { useNexusInfiniteQuery } from 'next-nexus/client';

Core Concepts

How It Works

The hook takes a definition factory function that accepts a page parameter (e.g., a cursor or page number). It calls this function sequentially to fetch pages. You must provide a getNextPageParam function that tells the hook how to get the parameter for the next page from the data of the last successfully fetched page.

Foreground vs. Background Revalidation

The revalidation logic for each page is identical to useNexusQuery. When fetching a new page (revalidateNext) or refetching an existing one (revalidatePage):

  • Foreground: If the page has no cached entry, or if keepStaleData is false and the entry is stale. This contributes to the isPending state.
  • Background: If a stale entry exists and keepStaleData is true. This contributes to the isPendingBackground state.

State Flags and UX

  • isPending: true during any foreground fetch. Use this to show a primary loading state (e.g., a skeleton screen on initial load, or a spinner on a “Load More” button).
  • isPendingBackground: true during any background fetch.
  • hasNextPage: true if getNextPageParam returned a value other than null or undefined for the last page.

Signature

Parameters

  • getDefinition: (param) => NexusDefinition<TPage> — A factory function that accepts the current page parameter and returns a GET definition.
  • options: An object to configure the hook. See Options below.

Return Value

An object containing:

  • data: { pages: TPage[], pageParams: unknown[] } | undefined
  • headers: Headers | undefined (from the most recent fetch)
  • error: Error | null
  • isPending, isPendingBackground, isSuccess, isError: boolean
  • hasNextPage: boolean
  • revalidateNext: () => Promise<void> (fetches the next page)
  • prefetchRef?: React.Ref<HTMLDivElement> (an optional ref for a sentinel element to enable prefetching)

Options

  • initialPageParam: The parameter for the very first page (e.g., 0 for page numbers, or null for cursor-based pagination).
  • getNextPageParam: (lastPage: TPage, allPages: TPage[]) => param | null | undefined — A function that returns the parameter for the next page, or null/undefined to indicate the end.
  • keepPages?: number - If set, keeps only the N most recent pages in memory to cap memory usage.
  • revalidateOnMount?: boolean (default: true)
  • revalidateOnWindowFocus?: boolean (default: false)
  • keepStaleData?: boolean (default: true)
  • prefetchNextOnNearViewport?: { rootMargin?: string, threshold?: number } - Enables prefetching the next page when a sentinel element is near the viewport.

Example

1. Definition Factory

First, create a definition that accepts a page parameter, like a cursor.

// src/api/productDefinition.ts (excerpt) export interface InfiniteProduct { products: { id: string; name: string }[]; nextCursor?: string | null; } export const productDefinition = { infiniteList: (cursor: string | null) => createApiDefinition<InfiniteProduct>({ method: "GET", endpoint: cursor ? `/products?cursor=${cursor}` : "/products", client: { tags: ["products", `cursor:${cursor ?? "first"}`], revalidate: 300, }, }), };

2. Component Usage

Then, use the hook in your component.

"use client"; import { useNexusInfiniteQuery } from "next-nexus/client"; import { productDefinition } from "@/api/productDefinition"; export default function InfiniteProductList() { const { data, hasNextPage, revalidateNext, prefetchRef, isPending } = useNexusInfiniteQuery(productDefinition.infiniteList, { initialPageParam: null, getNextPageParam: (lastPage) => lastPage?.nextCursor ?? null, prefetchNextOnNearViewport: { rootMargin: "200px" }, }); const allProducts = data?.pages.flatMap((page) => page.products) ?? []; return ( <div> <ul> {allProducts.map((p) => ( <li key={p.id}>{p.name}</li> ))} </ul> <button onClick={() => revalidateNext()} disabled={!hasNextPage || isPending} > {isPending ? "Loading…" : "Load More"} </button> {/* Optional: Sentinel element for prefetching */} <div ref={prefetchRef} style={{ height: 1 }} /> </div> ); }

See also

Last updated on