Rxova
Skip to content

Step behavior

Step configs keep static UI metadata and lifecycle behavior beside the step they describe.

const step = {
id: "review",
metadata: { title: "Review order" },
onLeave: async ({ snapshot, to }) => {
await analytics.track("review_left", { order: snapshot.context.orderId, to });
},
onEnter: ({ from, event, raise }) => {
if (event?.type === "SUBMIT") raise({ type: "AUDIT" });
}
};

Linear steps may be bare strings. Graph definitions use a record, so the key is the id and the config does not repeat it.

FieldMeaning
snapshotThe latest snapshot at the point the hook is called.
fromSource step, or null on initial entry.
toDestination step.
eventCausing graph event, or null for initial, linear, and timeline moves.
updateContextSynchronous immutable context update.
raiseQueue a graph event after the current move settles; a no-op in linear.

Attach transactional work to next or previous navigation:

await machine.navigate.goToNextStep({
run: async ({ snapshot }) => {
const validation = await validate(snapshot.context);
if (!validation.valid) throw new Error("Review is invalid");
return validation;
},
commit: ({ result, updateContext }) => {
updateContext((context) => ({ ...context, validatedAt: result.checkedAt }));
}
});

While run executes, phase is "working" and the source remains current. commit is synchronous; its updates and navigation publish atomically. A work failure returns reason: "error" without changing position or context.

onLeave runs after position commits. It is awaited, but returning a value has no navigation meaning and a failure cannot undo the move. Use it for cleanup, analytics, and other source effects.

onEnter runs after history and current-step state commit. It cannot cancel the move. While it runs, the destination has currentStep.async.isLoading: true and the transition phase is "entering".

An error is stored in currentStep.async.error and emitted through the named error subscription. The machine remains on the committed destination.

Graph transitions may declare onTransition. It runs after onLeave and before destination onEnter. A failure is reported with phase "transition", and onEnter still runs.

The runtime option applies one timeout to navigation run and every async hook invocation:

createGraphJourney(definition, { defaultTimeoutMs: 5_000 });

The timeout does not abort the underlying promise. Generation checks prevent stale completions from committing after terminate, restart, or dispose.