SDK
React hooks
Read Myna content from React components with request sharing, stale-while-revalidate, preview propagation, and Suspense.
@myna-sh/react provides hooks for reading content in React components. It wraps the public client and adds request sharing, loading and error state, stale-while-revalidate caching, and preview-token propagation.
React and @myna-sh/sdk are peer dependencies; the package has no others.
$ npm install @myna-sh/react @myna-sh/sdk
Setup
Create a client and pass it to MynaProvider:
import { createMyna } from "@myna-sh/sdk";
import { MynaProvider } from "@myna-sh/react";
import type { MynaCollections } from "./myna.generated";
const myna = createMyna<MynaCollections>({
project: "my-site",
previewToken: new URLSearchParams(location.search).get("preview") ?? undefined,
});
<MynaProvider client={myna}>
<App />
</MynaProvider>;
Every hook under the provider uses that client, including its preview token — so previewed and published pages render through the same components.
Hooks
import { useMynaEntries, useMynaEntry, useMynaSingleton } from "@myna-sh/react";
const posts = useMynaEntries<MynaCollections>("posts", { order: "-publishedAt", limit: 20 });
const post = useMynaEntry<MynaCollections>("posts", slug);
const settings = useMynaSingleton<MynaCollections>("site-settings");
| Hook | data |
|---|---|
useMynaEntries(collection, options?) |
{ data: Entry[], nextCursor } |
useMynaEntry(collection, slugOrId, options?) |
One entry |
useMynaSingleton(collection, options?) |
A singleton's entry |
Each returns:
| Field | Type | Meaning |
|---|---|---|
data |
T | undefined |
The result, once loaded |
error |
Error | undefined |
The most recent failure |
isLoading |
boolean |
No value yet |
isValidating |
boolean |
Refreshing with a value already on screen |
refetch |
() => void |
Discard the cached value and reload |
Pass undefined as slugOrId and useMynaEntry waits instead of fetching — useful while a route parameter resolves.
Options
Hooks accept every read option the SDK does — order, filter, fields, include, representation — with the same generated-type checking, plus:
| Option | Default | Meaning |
|---|---|---|
enabled |
true |
Set false to skip the read |
staleMs |
30000 |
How long a cached value is served before a background refresh |
suspense |
false |
Throw the pending promise for a <Suspense> boundary |
Behavior
Requests are shared. Components requesting the same collection with the same options produce one HTTP request — while in flight, and again within staleMs.
A failed refresh keeps the previous value. When a background refresh fails, data holds the last successful result and error is set. Render both if you want to show a staleness indicator.
Preview tokens propagate. A token on the provider's client applies to every hook beneath it. Reads return the collection as it would be published: updated entries replaced, created entries present, removed entries absent.
Using another data library
If your app already uses TanStack Query or SWR, call @myna-sh/sdk from it directly rather than adding these hooks — two caches holding the same content will disagree.
Server rendering and build-time reads
These hooks run on the client. For route loaders, server components, or static generation, call the SDK directly:
import { createMyna } from "@myna-sh/sdk";
const myna = createMyna<MynaCollections>({ project: "my-site" });
export async function loader() {
const posts = await myna.entries.list("posts", { order: "-publishedAt" });
return { posts: posts.data };
}
Responses carry an ETag and Cache-Control: public, max-age=0, must-revalidate, so a CDN or framework cache revalidates with a conditional request. To rebuild a static site when content changes, subscribe a deploy hook to the change_set.published webhook event.
