ResourceKit
API Reference

React hooks

The resourcekit/react bindings.

import {
  ResourceKitProvider,
  useSynced,
  useOne,
  useAction,
  useMutate,
  useEngine,
} from "resourcekit/react";

<ResourceKitProvider engine={...}>

Provides the engine to the tree. Wrap your app once, in a Client Component:

<ResourceKitProvider engine={appData}>{children}</ResourceKitProvider>

useSynced(query)

Subscribe to any query - local data instantly, background refresh, automatic updates after every write.

const { data, status, coverage, isRefreshing, error } = useSynced(
  issues.where({ workspaceId }).filter((i) => i.title.includes(search)),
);
FieldType
dataT[] for where(), T | null for one()Empty array / null while loading - never undefined
status"loading" | "stale" | "fresh" | "offline"What you're looking at
coverage"complete" | "partial" | "unknown"Whether the local set is provably whole
isRefreshingbooleanA background refresh is in flight
errorError | nullLast non-network refresh error

Good to know:

  • Components sharing a query share one request - render the same where() in ten places, the network sees it once.
  • Inline predicates are free. .filter() callbacks may close over props and state; changing them re-evaluates locally without refetching or resubscribing.
  • Built on useSyncExternalStore - concurrent-rendering safe, StrictMode safe.

useOne(resource, id)

Shorthand for useSynced(resource.one(id)).

const { data: issue } = useOne(issues, issueId);

useAction(write)

Bind any write - built-ins or actions - with pending/error state:

const assign = useAction(issues.actions.assign);
const create = useAction(issues.create);

await assign.run(issue.id, { userId });
Field
run(...args)Executes the write; UI updates instantly, promise resolves with the confirmed result
isPendingA run is awaiting confirmation
errorThe last rejection (already rolled back)
isConflictThe last run lost to a concurrent edit
reset()Clear the error state

Pass the resource method itself (issues.actions.assign, issues.create) rather than an inline arrow, so run stays referentially stable across renders.

useMutate()

The engine's mutate, for writes that don't need per-call state:

const mutate = useMutate();
await mutate(issues.delete(id));

usePreload(bundle, input?)

Prefetch a bundle of queries so a screen renders from cache. Runs on mount, re-runs when the input changes, and is cheap when the data is already local. Pass the input as the second argument (omit it for bundles that take none).

const { status, ready, error } = usePreload(workspaceData, { workspaceId });
Field
status"loading" | "ready" | "error"Where the prefetch stands
readybooleantrue once every query in the bundle is synced (or already local)
errorError | nullThe first query that failed, if any

useEngine()

The engine from context - for queuedWrites, flushWrites(), refresh(), or anything else on the engine API.

const engine = useEngine();
const queued = engine.queuedWrites;

On this page