useNexusQuery
useNexusQuery
is a client-side hook for fetching, caching, and revalidating data defined by a definition
. It’s designed for reading data in Client Components.
Import
import { useNexusQuery } from 'next-nexus/client';
Signature
useNexusQuery<TData, TSelectedData = TData>(
definition: NexusDefinition<TData>,
options?: { ... }
): {
data: TSelectedData | undefined
headers: Headers | undefined
error: Error | null
isPending: boolean
isPendingBackground: boolean
isSuccess: boolean
isError: boolean
revalidate: () => Promise<void>
}
definition
: AGET
definition object. The hook will throw an error if a non-GET definition is passed.options
: An optional object to configure the hook’s behavior. See Options below.
Core Concepts
Hydration-Aware Fetching
useNexusQuery
is aware of data fetched on the server and passed to the client via hydration. If data is available in the client cache upon mount, it will be rendered instantly without a new fetch, eliminating UI flickers.
Foreground vs. Background Revalidation
The hook automatically determines the revalidation mode when revalidate()
is called or when automatic revalidation events (mount, window focus) occur:
- Foreground: If no cached entry exists, or if
keepStaleData
isfalse
and the entry is stale. This setsisPending
totrue
. - Background: If a stale entry exists and
keepStaleData
istrue
(the default). This setsisPendingBackground
totrue
, whileisPending
remainsfalse
. - No-op: If a fresh entry exists, no fetch is performed.
State Flags and UX
isPending
:true
during a foreground fetch. Use this to show a loading state like a spinner, especially when no data is yet available (isPending && !data
).isPendingBackground
:true
during a background fetch. Use this to show a more subtle loading indicator (e.g., disabling a refresh button) while stale data remains visible.
Options
route?
:string
- Proxies the request through a Next.js Route Handler. When provided, the runtime clearsbaseURL
from thedefinition
and uses theroute
as the effective endpoint.enabled?
:boolean
(default:true
) - If set tofalse
, the hook will not fetch data or subscribe to cache updates.select?
:(data: TData) => TSelectedData
- A function to select or transform the data. The component will only re-render if the selected value changes.revalidateOnWindowFocus?
:boolean
(default:true
) - Automatically revalidates when the window is refocused.revalidateOnMount?
:boolean
(default:true
) - Automatically revalidates on mount if the data is stale.keepStaleData?
:boolean
(default:true
) - Iftrue
, stale data is kept on screen while a background revalidation occurs. Iffalse
,data
becomesundefined
during a foreground revalidation.
Examples
Basic Usage
'use client';
import { useNexusQuery } from 'next-nexus/client';
import { productDefinition } from '@/api/productDefinition';
export function ProductListClient() {
const { data, isPending } = useNexusQuery(productDefinition.list);
if (isPending && !data) return <div>Loading...</div>;
const products = data ?? [];
return (
<ul>
{products.map(p => (
<li key={p.id}>{p.name}</li>
))}
</ul>
);
}
Using the select
Option
'use client';
import { useNexusQuery } from 'next-nexus/client';
import { statsDefinition } from '@/api/statsDefinition';
export function TotalCount() {
const { data: count } = useNexusQuery(statsDefinition.summary, {
select: s => s.total,
});
return <div>Total: {count ?? 0}</div>;
}
Using a route
Override
'use client';
import { useNexusQuery } from 'next-nexus/client';
import { productDefinition } from '@/api/productDefinition';
export function ProductListViaRoute() {
const { data } = useNexusQuery(productDefinition.list, { route: '/api/products' });
return <div>{data?.length ?? 0} items</div>;
}
Reading Cached Headers
'use client';
import { useNexusQuery } from 'next-nexus/client';
import { listWithTotalDefinition } from '@/api/productDefinition'; // Assuming this exists
export function ProductListWithTotal() {
const { data, headers } = useNexusQuery(listWithTotalDefinition);
const total = headers?.get('x-total-count');
return (
<div>
Items: {data?.length ?? 0} / Total: {total ?? 'n/a'}
</div>
);
}
See also
Last updated on