AI agents: fetch the documentation index at llms.txt. Markdown versions are available by appending .md to any page URL, including this page's markdown.
Hooks
React hooks for data, connection state, and client access in the sync engine.
import { Suspense } from "react";
import { useModel } from "@stratasync/react";
function TaskDetail({ taskId }: { taskId: string }) {
const task = useModel<Task>("Task", taskId);
if (!task) {
return <div>Task not found</div>;
}
return <div>{task.title}</div>;
}
// Wrap in Suspense boundary
function TaskPage({ taskId }: { taskId: string }) {
return (
<Suspense fallback={<div>Loading...</div>}>
<TaskDetail taskId={taskId} />
</Suspense>
);
}Signature: useModel<T>(modelName: string, id: string | null | undefined): T | null
| Parameter | Type | Description |
|---|---|---|
modelName | string | Registered model name. |
id | string | null | undefined | Model ID. Returns null immediately if null or undefined. |
Return value: T | null: the model instance or null if not found.
Non-Suspense alternative to useModel. Returns explicit loading and error states.
import { useModelState } from "@stratasync/react";
function TaskDetail({ taskId }: { taskId: string }) {
const {
data: task,
isLoading,
isFound,
error,
refresh,
} = useModelState<Task>("Task", taskId);
if (isLoading) {
return <div>Loading...</div>;
}
if (error) {
return <div>Error: {error.message}</div>;
}
if (!isFound) {
return <div>Task not found</div>;
}
return (
<div>
<h1>{task.title}</h1>
<button onClick={refresh}>Refresh</button>
</div>
);
}Signature: useModelState<T>(modelName: string, id: string | null | undefined): UseModelResult<T>
UseModelResult:
| Field | Type | Description |
|---|---|---|
data | T | null | The model instance. |
isLoading | boolean | Whether the model is being loaded. |
isFound | boolean | Whether the model was found (data !== null). |
error | Error | null | Any error that occurred during loading. |
refresh | () => Promise<void> | Manually re-fetch the model. |
Alias for useModel that makes the Suspense dependency explicit.
import { useModelSuspense } from "@stratasync/react";
function TaskDetail({ taskId }: { taskId: string }) {
const task = useModelSuspense<Task>("Task", taskId);
// Same behavior as useModel
}Signature: useModelSuspense<T>(modelName: string, id: string): T | null
Queries models with filtering, sorting, and pagination. Returns loading states explicitly.
import { useQuery } from "@stratasync/react";
function TaskList({ projectId }: { projectId: string }) {
const {
data: tasks,
isLoading,
hasMore,
totalCount,
refresh,
} = useQuery<Task>("Task", {
where: (task) => task.projectId === projectId,
orderBy: (a, b) => a.createdAt - b.createdAt,
limit: 20,
});
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div>
<p>
Showing {tasks.length} of {totalCount} tasks
</p>
<ul>
{tasks.map((task) => (
<li key={task.id}>{task.title}</li>
))}
</ul>
{hasMore && <button onClick={refresh}>Load more</button>}
</div>
);
}Signature: useQuery<T>(modelName: string, options?: UseQueryOptions<T>): UseQueryResult<T>
UseQueryOptions (extends QueryOptions):
| Option | Type | Default | Description |
|---|---|---|---|
where | (item: T) => boolean | - | Filter predicate. |
orderBy | (a: T, b: T) => number | - | Sort comparator. |
limit | number | - | Maximum results. |
offset | number | - | Results to skip. |
includeArchived | boolean | false | Include archived items. |
skip | boolean | false | Skip the query entirely. |
UseQueryResult:
| Field | Type | Description |
|---|---|---|
data | T[] | Query results. |
isLoading | boolean | Whether the query is executing. |
error | Error | null | Any error that occurred. |
totalCount | number | undefined | Total matching count before pagination. |
hasMore | boolean | Whether more results are available. |
refresh | () => Promise<void> | Re-execute the query. |
Convenience wrapper around useQuery without pagination (limit/offset).
import { useQueryAll } from "@stratasync/react";
function AllTasks() {
const { data: tasks, isLoading } = useQueryAll<Task>("Task", {
where: (t) => t.status !== "done",
orderBy: (a, b) => a.title.localeCompare(b.title),
});
if (isLoading) {
return <div>Loading...</div>;
}
return <TaskGrid tasks={tasks} />;
}Signature: useQueryAll<T>(modelName: string, options?: Omit<UseQueryOptions<T>, "limit" | "offset">): UseQueryResult<T>
Returns the count of matching models without fetching them.
import { useQueryCount } from "@stratasync/react";
function TaskCounter({ projectId }: { projectId: string }) {
const { count, isLoading } = useQueryCount<Task>(
"Task",
(task) => task.projectId === projectId && task.status === "todo"
);
if (isLoading) {
return <span>...</span>;
}
return <span>{count} tasks</span>;
}Signature: useQueryCount<T>(modelName: string, where?: (item: T) => boolean): { count: number; isLoading: boolean; error: Error | null }
| Field | Type | Description |
|---|---|---|
count | number | Number of matching models. |
isLoading | boolean | Whether the count is being computed. |
error | Error | null | Any error that occurred. |
Returns sync status, last sync ID, pending count, and error state.
import { useConnectionState } from "@stratasync/react";
function SyncStatusBadge() {
const { status, lastSyncId, backlog, error } = useConnectionState();
if (error) {
return <Badge color="red">Error: {error.message}</Badge>;
}
if (status === "bootstrapping") {
return <Badge color="yellow">Bootstrapping...</Badge>;
}
if (status === "syncing") {
return (
<Badge color="green">
Synced (ID: {lastSyncId}) {backlog > 0 && `- ${backlog} pending`}
</Badge>
);
}
return <Badge color="gray">{status}</Badge>;
}Signature: useConnectionState(): UseConnectionStateResult
UseConnectionStateResult:
| Field | Type | Description |
|---|---|---|
status | SyncClientState | Current sync state: "disconnected", "connecting", "bootstrapping", "syncing", or "error". |
lastSyncId | number | Last sync ID received from the server. |
backlog | number | Number of pending (unsynced) transactions in the outbox. |
error | Error | null | Last sync error, or null if no error. |
Returns true when the sync client's connection state is "disconnected".
import { useIsOffline } from "@stratasync/react";
function OfflineBanner() {
const isOffline = useIsOffline();
if (!isOffline) {
return null;
}
return <div>You're offline. Changes will sync when you reconnect.</div>;
}Signature: useIsOffline(): boolean
Returns the count of unsynced transactions.
import { usePendingCount } from "@stratasync/react";
function PendingIndicator() {
const { count, hasPending } = usePendingCount();
if (!hasPending) {
return <span>All changes saved</span>;
}
return <span>{count} changes pending sync</span>;
}Signature: usePendingCount(): UsePendingCountResult
UsePendingCountResult:
| Field | Type | Description |
|---|---|---|
count | number | Number of pending transactions. |
hasPending | boolean | true when count > 0. |
Trigger a manual sync cycle.
import { useSync } from "@stratasync/react";
function SyncButton() {
const { sync, isSyncing } = useSync();
return (
<button onClick={sync} disabled={isSyncing}>
{isSyncing ? "Syncing..." : "Sync Now"}
</button>
);
}Signature: useSync(): { sync: () => Promise<void>; isSyncing: boolean }
| Field | Type | Description |
|---|---|---|
sync | () => Promise<void> | Triggers client.syncNow(). Guards against concurrent calls. |
isSyncing | boolean | true while a manual sync is in progress. |
Returns the full sync context: client instance, connection state, and derived flags.
import { useSyncClient } from "@stratasync/react";
function SyncDebugPanel() {
const {
client,
state,
connectionState,
lastSyncId,
backlog,
error,
isReady,
isSyncing,
isOffline,
clientId,
} = useSyncClient();
return (
<pre>
{JSON.stringify(
{
state,
connectionState,
lastSyncId,
backlog,
isReady,
isOffline,
clientId,
},
null,
2
)}
</pre>
);
}Signature: useSyncClient(): SyncContextValue
SyncContextValue:
| Field | Type | Description |
|---|---|---|
client | SyncClient | The sync client instance. |
state | SyncClientState | Current sync state. |
connectionState | ConnectionState | Current connection state. |
lastSyncId | number | Last sync ID from server. |
backlog | number | Pending transaction count. |
error | Error | null | Last sync error. |
isReady | boolean | true when state is "syncing". |
isSyncing | boolean | true when state is "syncing" or "bootstrapping". |
isOffline | boolean | true when connection is "disconnected". |
clientId | string | Client instance identifier. |
Throws an error if called outside of a SyncProvider.
Returns the SyncClient instance for calling client methods directly.
import { useSyncClientInstance } from "@stratasync/react";
function CreateTaskButton() {
const client = useSyncClientInstance();
const handleCreate = async () => {
await client.create("Task", {
title: "New task",
status: "todo",
});
};
return <button onClick={handleCreate}>Create Task</button>;
}Signature: useSyncClientInstance(): SyncClient
true when bootstrapping is complete and the client is in "syncing" state. Gate UI rendering until data is available.
import { useSyncReady } from "@stratasync/react";
function AppContent() {
const isReady = useSyncReady();
if (!isReady) {
return <FullPageLoader />;
}
return <Dashboard />;
}Signature: useSyncReady(): boolean
Returns the current SyncClientState string value.
import { useSyncState } from "@stratasync/react";
function StateIndicator() {
const state = useSyncState();
const labels: Record<string, string> = {
disconnected: "Disconnected",
connecting: "Connecting...",
bootstrapping: "Loading data...",
syncing: "Ready",
error: "Error",
};
return <span>{labels[state] ?? state}</span>;
}Signature: useSyncState(): SyncClientState
Returns one of: "disconnected", "connecting", "bootstrapping", "syncing", "error".