Hooks
React hooks for fetching uidu data on the client, accessing the client, and normalizing CMS data.
useQuery fetches data in Client Components. useUiduClient and useUidu read the client from context. useFields and toText are pure transforms for CMS field values, safe on the server too. Custom apps framed inside uidu also get useUiduApp, covered in Custom apps. The @uidu/react reference lists every export.
In Server Components you don't need any of these: await a @uidu/client function directly.
useQuery(document, variables?, options?)
Run any generated @uidu/client document from a Client Component. It uses SWR over the client from the nearest UiduProvider: results are cached and deduplicated by operation name + variables, and revalidate on focus by default.
'use client';
import { useQuery } from '@uidu/react';
import { ListEventsDocument } from '@uidu/client';
export function UpcomingEvents() {
const { data, error, isLoading } = useQuery(ListEventsDocument, { first: 10 });
if (isLoading) return <p>Loading…</p>;
if (error) return <p>Couldn't load events.</p>;
const events = data?.currentWorkspace?.events?.edges?.map((e) => e?.node) ?? [];
return <ul>{events.map((ev) => ev && <li key={ev.id}>{ev.name}</li>)}</ul>;
}| Arguments | document — any *Document exported by @uidu/client; variables — its typed variables; options — revalidateOnFocus, revalidateOnReconnect, refreshInterval |
| Returns | { data, error, isLoading, mutate } — data is the raw query result (the GraphQL shape, not the flattened array a list* function returns) |
| Runtime | Client only — requires UiduProvider |
Raw shape
useQuery returns what the query returns, so connections come as edges[].node. The list* functions in @uidu/client flatten that for you; with useQuery you do it yourself, as above.
There are no per-domain hooks (useEvents, usePage…) yet: useQuery plus a generated document covers the same ground.
useUiduClient()
Read the client instance from any Client Component descendant of UiduProvider.
'use client';
import { useUiduClient } from '@uidu/react';
import { search } from '@uidu/client';
export function SearchButton({ q }: { q: string }) {
const client = useUiduClient();
async function run() {
// any @uidu/client function works with this client
const results = await search(client, {
params: { filters: [{ field: 'name', op: 'matches', value: q }] },
});
console.log(results);
}
return <button onClick={run}>Search</button>;
}| Returns | UiduClient instance |
| Throws | Error with a descriptive message if called outside UiduProvider |
| Runtime | Client only — requires React context |
Server Components
Don't call useUiduClient() from a Server Component. Server Components should import the server-side client directly from lib/uidu.ts (the one with the API key).
useUidu()
Lower-level accessor — returns the full provider context: the client plus the resolved endpoint URL. Rarely needed in app code; prefer useUiduClient() unless you specifically need the endpoint.
'use client';
import { useUidu } from '@uidu/react';
export function DebugInfo() {
const { client, endpoint } = useUidu();
return <code>{endpoint}</code>;
}| Returns | { client: UiduClient, endpoint: string } |
| Throws | Error if called outside UiduProvider |
useFields(fieldValues)
Normalize a fieldValues array (from a CMS page block) into a { shortname: value } map. Pure function — safe to call from Server Components, Client Components, or anywhere else. The use prefix is a naming convention only; no React state or effects are involved.
import type { Page } from '@uidu/client';
import { useFields, toText } from '@uidu/react';
type PageBlock = NonNullable<Page['pageBlocks']>[number];
export function Hero({ block }: { block: PageBlock }) {
const fields = useFields(block.fieldValues);
return (
<header>
<h1>{toText(fields.Titolo)}</h1>
<p>{toText(fields.Sottotitolo)}</p>
</header>
);
}Three kinds of values
useFields handles the three shapes a uidu field value can take:
Field kind | Output |
|---|---|
| Scalar (text, number, boolean, etc.) | fieldValue.content.value — the raw value |
| Collection | fieldValue.content — the whole content object (typically { items: [...] }) |
| Linked record | fieldValue.linkedRecord — the embedded record (e.g. a Form, a Contact) |
Field values without a shortname are dropped.
| Returns | Record<string, unknown> |
| Pure | Yes — no React state or effects |
| Runtime | Anywhere |
toText(value) (utility)
Flatten any field value to a plain string. Handles raw strings, numbers, arrays of nodes, and Slate-style rich text trees ({ type, children }, { text }). Used in tandem with useFields to handle the case where the CMS stores a "title" field as either a plain string or a rich-text fragment.
toText('hello'); // → 'hello'
toText(42); // → '42'
toText({ type: 'paragraph', children: [{ text: 'hi' }] }); // → 'hi'
toText([{ text: 'a ' }, { text: 'b', bold: true }]); // → 'a b'
toText(null); // → ''For genuine rich text (not just a single string), use <RichText> — it renders the same tree as React elements with proper marks, lists, headings, and so on.
| Returns | string (empty string when value is null/undefined/unhandled) |
| Pure | Yes |
| Runtime | Anywhere |