Skip to content
Strata Sync

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.

All hooks require a SyncProvider. They re-render automatically when data changes.

useModel

Reads a single model by ID. Suspends while bootstrapping or loading a lazy model.

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

ParameterTypeDescription
modelNamestringRegistered model name.
idstring | null | undefinedModel ID. Returns null immediately if null or undefined.

Return value: T | null: the model instance or null if not found.

useModelState

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:

FieldTypeDescription
dataT | nullThe model instance.
isLoadingbooleanWhether the model is being loaded.
isFoundbooleanWhether the model was found (data !== null).
errorError | nullAny error that occurred during loading.
refresh() => Promise<void>Manually re-fetch the model.

useModelSuspense

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

useQuery

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):

OptionTypeDefaultDescription
where(item: T) => boolean-Filter predicate.
orderBy(a: T, b: T) => number-Sort comparator.
limitnumber-Maximum results.
offsetnumber-Results to skip.
includeArchivedbooleanfalseInclude archived items.
skipbooleanfalseSkip the query entirely.

UseQueryResult:

FieldTypeDescription
dataT[]Query results.
isLoadingbooleanWhether the query is executing.
errorError | nullAny error that occurred.
totalCountnumber | undefinedTotal matching count before pagination.
hasMorebooleanWhether more results are available.
refresh() => Promise<void>Re-execute the query.

useQueryAll

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>

useQueryCount

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 }

FieldTypeDescription
countnumberNumber of matching models.
isLoadingbooleanWhether the count is being computed.
errorError | nullAny error that occurred.

useConnectionState

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:

FieldTypeDescription
statusSyncClientStateCurrent sync state: "disconnected", "connecting", "bootstrapping", "syncing", or "error".
lastSyncIdnumberLast sync ID received from the server.
backlognumberNumber of pending (unsynced) transactions in the outbox.
errorError | nullLast sync error, or null if no error.

useIsOffline

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

usePendingCount

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:

FieldTypeDescription
countnumberNumber of pending transactions.
hasPendingbooleantrue when count > 0.

useSync

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 }

FieldTypeDescription
sync() => Promise<void>Triggers client.syncNow(). Guards against concurrent calls.
isSyncingbooleantrue while a manual sync is in progress.

useSyncClient

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:

FieldTypeDescription
clientSyncClientThe sync client instance.
stateSyncClientStateCurrent sync state.
connectionStateConnectionStateCurrent connection state.
lastSyncIdnumberLast sync ID from server.
backlognumberPending transaction count.
errorError | nullLast sync error.
isReadybooleantrue when state is "syncing".
isSyncingbooleantrue when state is "syncing" or "bootstrapping".
isOfflinebooleantrue when connection is "disconnected".
clientIdstringClient instance identifier.

Throws an error if called outside of a SyncProvider.

useSyncClientInstance

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

useSyncReady

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

useSyncState

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".