# 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](/sdk/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. ```bash $ npm install @myna-sh/react @myna-sh/sdk ``` ## Setup Create a client and pass it to `MynaProvider`: ```tsx import { createMyna } from "@myna-sh/sdk"; import { MynaProvider } from "@myna-sh/react"; import type { MynaCollections } from "./myna.generated"; const myna = createMyna({ project: "my-site", previewToken: new URLSearchParams(location.search).get("preview") ?? undefined, }); ; ``` Every hook under the provider uses that client, including its [preview token](/concepts/previews) — so previewed and published pages render through the same components. ## Hooks ```tsx import { useMynaEntries, useMynaEntry, useMynaSingleton } from "@myna-sh/react"; const posts = useMynaEntries("posts", { order: "-publishedAt", limit: 20 }); const post = useMynaEntry("posts", slug); const settings = useMynaSingleton("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](/sdk/public-client) the SDK does — `order`, `filter`, `fields`, `include`, `representation` — with the same [generated-type checking](/schema/generated-types), 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 `` 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: ```ts import { createMyna } from "@myna-sh/sdk"; const myna = createMyna({ 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](/webhooks/events).