ReactiveActionStore

type ReactiveActionStore<TArgs, TResult> = object;

A framework-agnostic state machine that wraps an async function and exposes a { dispatch, getState, subscribe, reset } contract. Bridges trivially into useSyncExternalStore, Svelte stores, Vue's shallowRef, and similar reactive primitives.

See

createReactiveActionStore

Type Parameters

Type Parameter
TArgs extends readonly unknown[]
TResult

Properties

dispatch

readonly dispatch: (...args) => void;

Fire-and-forget dispatch. Returns undefined synchronously and never throws — failures surface on state as { status: 'error' }, and superseded or reset()-aborted calls produce no state update. Use from UI event handlers; there's no promise to handle or .catch.

Parameters

ParameterType
...argsTArgs

Returns

void

See


dispatchAsync

readonly dispatchAsync: (...args) => Promise<TResult>;

Promise-returning dispatch for imperative callers. Resolves with the wrapped function's result on success. Rejects with the thrown error on failure, and with an AbortError when the call is superseded or reset() is invoked — filter those with isAbortError from @solana/promises.

Parameters

ParameterType
...argsTArgs

Returns

Promise<TResult>


getState

readonly getState: () => ReactiveActionState<TResult>;

Returns the current state.

Returns

ReactiveActionState<TResult>


reset

readonly reset: () => void;

Aborts any in-flight dispatch and resets the state to { status: 'idle' }.

Returns

void


subscribe

readonly subscribe: (listener) => () => void;

Registers a listener called on every state change. Returns an unsubscribe function.

Parameters

ParameterType
listener() => void

Returns

() => void


withSignal

readonly withSignal: (signal) => object;

Returns a thin wrapper exposing dispatch / dispatchAsync that compose signal with the store's internal per-dispatch controller via AbortSignal.any — aborting either cancels the in-flight call. Aborting the caller-provided signal surfaces the abort reason on state as { status: 'error' }; the internal controller path (supersession by a newer dispatch or reset()) is silent by design so the newer dispatch owns state. Use this to attach a caller-provided cancellation source (per-attempt timeout, shared kill switch, parent-context signal) without touching the bare dispatch / dispatchAsync API.

  • Per-attempt timeout: store.withSignal(AbortSignal.timeout(5_000)).dispatch(args) — fresh clock per call.
  • Permanent kill switch: hold one AbortController, bind the wrapper once (const killable = store.withSignal(killCtrl.signal)), and use killable.dispatch(...) everywhere; aborting the controller cancels in-flight and short-circuits future calls.

The wrapper exposes only dispatch / dispatchAsyncgetState / subscribe / reset remain store-level concerns on the parent.

Parameters

ParameterType
signalAbortSignal

Returns

object

NameType
dispatch()(...args) => void
dispatchAsync()(...args) => Promise<TResult>

On this page