Effects
An effect is a function that runs every time the actor enters a state. It does side-effect work and emits events back into the machine. It does not transition the machine directly.
EffectInput
Section titled “EffectInput”{ signal: AbortSignal; state: { name: string; payload: unknown }; event: InternalEvent; context: Context<ActorContext>; emit: (event) => void; clock: Clock;}- Run on every entry, initial state included (
event.typeis"__init"at construction) - Terminal states run entry effects too (emit completion outputs to parents)
- Return value is ignored. Effects emit; the machine reacts.
- Never throw. Catch and emit an internal error event instead.
Auto-abort
Section titled “Auto-abort”signal fires when the actor leaves the state. Check it before emitting.
m.effect(submitting, { name: "chargeCard", fn: ({ signal, emit }) => { chargeCard(cardNumber).then((orderId) => { if (!signal.aborted) emit(paymentOk.create({ orderId })); }); },});Post-abort emit is a silent no-op anyway. The guard skips the wasted call.
Multiple effects
Section titled “Multiple effects”Call m.effect multiple times for one state. They run in order.
m.effect(submitting, { name: "chargeCard", fn: ({ signal, emit }) => { chargeCard(cardNumber).then( (id) => { if (!signal.aborted) emit(paymentOk.create({ orderId: id })); }, (err) => { if (!signal.aborted) emit(paymentFail.create({ reason: String(err) })); }, ); },});m.effect(submitting, { name: "startSubmitTimeout", fn: ({ signal, emit, clock }) => { clock.setTimeout(800, () => { if (!signal.aborted) emit(submittingDone.create()); }); },Error handling
Section titled “Error handling”An uncaught error moves the actor to the built-in terminal __error state.
snapshot().done becomes true, snapshot().error carries the failure. The
actor stops accepting events.