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
isfalse
and the entry is stale. This contributes to theisPending
state. - Background: If a stale entry exists and
keepStaleData
istrue
. This contributes to theisPendingBackground
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
ifgetNextPageParam
returned a value other thannull
orundefined
for the last page.
Signature
Parameters
getDefinition
:(param) => NexusDefinition<TPage>
— A factory function that accepts the current page parameter and returns aGET
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, ornull
for cursor-based pagination).getNextPageParam
:(lastPage: TPage, allPages: TPage[]) => param | null | undefined
— A function that returns the parameter for the next page, ornull
/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