React hooks
The exact surface of ramose/react, one section per export. This page is for React developers who have read Live queries and want the signatures.
New here? Start with Getting started.
import { RamoseProvider, useRamose, useDb, useLive, useQuery, usePull, useBasis, useTransact, errorMessage } from "ramose/react";Hooks only, no UI. They reach the Ramose server through one client. useLive, useQuery, usePull and useBasis take a db explicitly, so they work with db.asOf(t) and db.history too. The Ramose server is the one Cloudflare Worker that serves all your databases; Ramose’s code calls it the peer.
The result types are exported alongside the hooks: Live (useLive, usePull), Async (useQuery), Transact (useTransact) and RamoseProviderProps.
RamoseProvider
Section titled “RamoseProvider” <RamoseProvider key={open.workspace.slug} url={RAMOSE_URL} token={open.workspace.token} >RamoseProvider(props: ClientOptions & { children }) — owns one client (glossary) made with Ramose.connect, and closes it on unmount or when url / token / fetch / webSocket change.
tokenmust be a stable token source (glossary) — module scope oruseMemo, never built inline.- One customer per client: switch workspaces with React’s
key, as Reef does.
const db = useDb(slug, Reef);useDb(name, catalog): Db<C> — client.db(name, catalog) from the nearest provider, kept stable on [client, name, catalog]. Pass a module-scope schema. useRamose(): Client returns the provider’s client itself. Both throw outside a provider.
const client = useRamose();useLive
Section titled “useLive”const TodoList = () => { const { rows, error } = useLive(db, todoQuery); if (error !== undefined) return <p>offline…</p>; if (rows === undefined) return <p>loading…</p>; return ( <ul> {rows.map((row) => ( <TodoRowView key={row.id} row={row} /> ))} </ul> );};useLive(db, query, params?): { rows, error, ticks } — a live query as React state: it re-runs whenever the database changes (glossary). Needs no provider. Bind Ramose.params as the third argument; a params-only change keeps the last rows.
rowsisundefineduntil the first answer, and again right afterdborquerychange.erroris a terminal failure only (InvalidRequest,DatabaseNotFound,Unauthorized,QueryBudgetExceeded); network trouble is retried in place. Ondb.asOf(t)the query runs once and the rows stay.tickscounts updates after the first — Reef’s “live” pill pulses on it.key={row.id}: a selectedid: X.idis a plainnumber.
A second form, useLive(stream), drains any Stream you built yourself (db.live(q), db.livePull(...)) with the same result shape.
useQuery
Section titled “useQuery” const past = useQuery(t === undefined ? db : db.asOf(t), boardQuery);useQuery(db, query, params?): { data, error, loading } — one db.q per db / query / params triple. While a new run is loading the previous data stays, so a time-travel slider never flashes empty; a slower older answer never overwrites a newer one.
usePull
Section titled “usePull” const extra = usePull(db, { id: issueId }, issueExtraShape).rows ?? null;usePull(db, subject, shape): { rows: Pull | null, error, ticks } — one record, live. rows is the record or null (missing, deleted, or a required field hidden from you). { id } inline is fine; hoist the shape.
useBasis
Section titled “useBasis” const maxT = useBasis(db);useBasis(db): number | undefined — the version number this view reads at (glossary), refreshed on every update. Reef uses it as the slider’s upper bound. useBasis(db.asOf(t)) answers t at once with no request.
useTransact
Section titled “useTransact” const { run } = useTransact({ onError: (error) => toast("error", errorMessage(error)), });const TodoRowView = ({ row }: { row: TodoRow }) => { const { run } = useTransact();useTransact(options?): { run, pending, error, clearError } — runs a write (glossary) or any Effect from an event handler. Needs no provider and takes no db.
run(effect): Promise<Exit>— resolves instead of throwing, soonClick={() => void run(...)}is safe.pendingistruewhile any run is in flight;errorholds the last failure until a run succeeds orclearError();onErrorfires per failure.
errorMessage
Section titled “errorMessage”errorMessage(e); // e.message ?? e._tag ?? String(e)errorMessage(error: unknown): string — the one-liner for a toast; a policy denial shows the server’s message, e.g. retract denied on :issue/status.
- Stable token source. Build it once per sign-in, not per render.
- Hoist queries and shapes to module scope; they are compared by identity.
db,db.asOf(t)and{ id }subjects are compared by value, so inline is fine. - One client per customer. Remount the provider with
key={slug}when the workspace changes. key={row.id}in lists; the id is anumber.erroris not the same shape in every hook.useLive,useQueryandusePullreport an EffectCause;useTransactreports the failure itself. So a toast iserrorMessage(Cause.squash(error))from a read hook anderrorMessage(error)fromuseTransact.