Skip to main content
A computation’s results reach React in one of two ways:
  • A dashboard follows the current result. A maintained result refreshes in the background and the UI reads whichever accepted result is selected.
  • A user starts a run and follows it. A report or simulation runs when the user asks, and the UI follows that specific run.
Both read through ordinary reactive queries. Rendering, remounting and reconnecting never start work.

Follow a maintained result

Declare the maintained result next to the computation. latestResultPolicy is the common dashboard policy: refresh when the result is stale or its inputs were invalidated, coalesce overlapping demand into one run in flight, and serve each result as soon as it is accepted. Freshness, stale grace and retention stay your choices.
bijection/maintained.ts
Override a single choice by spreading the policy first, for example select: { by: "manual" } for a result a reviewer approves.
The UI reacts as soon as the selection or its serving state changes. The calculation itself refreshes on its own schedule: a reactive read of an external Spark result is current with its selection, not with your source tables. Use ctx.computations.read in an ordinary query when a calculation must be transactionally current with native tables.

Run a calculation on demand

Declare a public computation with one access policy per control. Starting, reading, cancelling and retiring are different permissions; reuse your own policy helpers instead of assuming one implies another. An omitted cancel or retire policy denies it. Holding a generated computation reference grants nothing.
bijection/reports.ts
The generated reference is api.reports.revenue. useRun starts and recovers runs; useOutputs(run, outputs) follows one run’s outputs. useComputation composes both for a screen that starts and shows its own latest run.
report.start(args) resolves with the run once admission is established; rows arrive later in report.view. Each start after a decision admits new work. To keep showing another run, compose useRun and useOutputs directly. report.status is one of: An unresolved submission keeps its identity. recover() resubmits the original request with its original arguments and never creates a second run; start refuses until the submission is resolved. The request journal survives reloads, so remounting a component restores the same run.

Read run state

useOutputs, like useComputation’s view, returns idle, loading, pending, unavailable or available. A pending run reports a summary: its phase, whether cancellation was requested, and the first error diagnostic. A run that ended without output reports the same summary on its absent reason, so the UI can tell a failed run from a cancelled one:
The inspect endpoint keeps the complete inspection protocol for debugging: attempts, evidence, custody, measurements and every diagnostic.

Pages and errors

Row outputs use the same shape as usePaginatedQuery: results, status (CanLoadMore, LoadingMore or Exhausted), isLoading and loadMore(numItems). The first page arrives with the observation; select its size with initialNumItems.
  • Expected lifecycle conditions are typed state: pending, or unavailable with an absent, unknown, withheld or unavailable reason.
  • A failed first read throws from the hook, like useQuery, and reaches your error boundary.
  • A failed continuation keeps every row already loaded and sets that output’s error to the query’s own error, including ConvexError data. The page stays subscribed.
  • A changed maintained selection, revoked access or withheld result discards loaded rows; pages from different selections are never mixed.

Select exact inputs

Dataset inputs are exact versions chosen on the server. The dataset owner returns the typed input directly:
Admission acquires its own pin on the selected version and checks access again. A run keeps that version even after newer ones are published.