ReactiveActionStore
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
Type Parameters
| Type Parameter |
|---|
TArgs extends readonly unknown[] |
TResult |
Properties
dispatch
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
| Parameter | Type |
|---|---|
...args | TArgs |
Returns
void
See
- ReactiveActionStore.dispatchAsync when you need the resolved value or propagated errors.
- ReactiveActionStore.withSignal to attach a caller-provided
AbortSignalto a dispatch.
dispatchAsync
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
| Parameter | Type |
|---|---|
...args | TArgs |
Returns
Promise<TResult>
getState
Returns the current state.
Returns
ReactiveActionState<TResult>
reset
Aborts any in-flight dispatch and resets the state to { status: 'idle' }.
Returns
void
subscribe
Registers a listener called on every state change. Returns an unsubscribe function.
Parameters
| Parameter | Type |
|---|---|
listener | () => void |
Returns
() => void
withSignal
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 usekillable.dispatch(...)everywhere; aborting the controller cancels in-flight and short-circuits future calls.
The wrapper exposes only dispatch / dispatchAsync — getState / subscribe / reset
remain store-level concerns on the parent.
Parameters
| Parameter | Type |
|---|---|
signal | AbortSignal |
Returns
object
| Name | Type |
|---|---|
dispatch() | (...args) => void |
dispatchAsync() | (...args) => Promise<TResult> |