Side-effects
Side-effects allow your state-machines to interact with the outside world.
In yay-machine you can optionally run side-effects.
- when the machine is started or stopped
- when a state is entered or exited
- during a transition
Side-effects are just functions
In yay-machine side-effects are just functions.
The side-effect function MAY return a cleanup function, which you can use to free resources (eg, clear timers, release connections, etc).
type Cleanup = () => void;
type SideEffect = (param: { /* ... */}) => Cleanup | null | undefined | void;
Side-effect lifetime
The lifetime of a side-effect matches the lifetime of where it is defined.
More concretely
- a machine
onStart()
side-effect MAY run as long as the machine is running (not stopped). When the machine is stopped, the machine’sonStart()
side-effect is cleaned-up (the returned cleanup function (if any) is called, and the side-effect may no longersend()
the machine events) - a state
onEnter()
side-effect MAY run as long as the machine remains in that state. When the machine exits that state via a transition (or the machine is stopped), the state’sonEnter()
side-effect is cleaned-up (the returned cleanup function (if any) is called, and the side-effect may no longersend()
the machine events) - a transition
onTransition()
side-effect is transient, since it only exists for the transition, so it is cleaned-up immediately - a state
onExit()
side-effect is transient, since it only exists while exiting the state, so it is cleaned-up immediately - a machine
onStop()
side-effect is transient, since it only exists while stopping the machine, so it is cleaned-up immediately
Machine onStart()
, onStop()
These two optional side-effects are run when the machine is started/stopped
const machine = defineMachine<State, Event>({ onStart: ({ state, send }) => { /* ... */ }, onStop: ({ state }) => { /* ... */ }, // ...});
They receive a single parameter containing the machine’s current state
and a send()
function, which can be used to send events to the machine instance.
State onEnter()
, onExit()
These two optional side-effects are run when a specific state is entered or exited
const machine = defineMachine<State, Event>({ states: { [stateName]: { onEnter: ({ state, event, send }) => { /* ... */ }, onExit: ({ state, event, send }) => { /* ... */ }, }, }, // ...});
Like machine-lifecycle side-effects, they receive a single parameter containing the machine’s current state
and a send()
function, which can be used to send events to the machine instance. Depending on what triggered the state-entry, they may receive an event
too.
Transition onTransition()
This optional side-effect is run during a transition from a specific state or any state
const machine = defineMachine<State, Event>({ states: { [stateName]: { on: { [EVENT_TYPE]: { to: "nextStateName", onTransition: ({ state, event, next, send }) => { /* ... */ }, }, }, }, }, // ...});
And/or
const machine = defineMachine<State, Event>({ on: { [EVENT_TYPE]: { to: "nextStateName", onTransition: ({ state, event, send }) => { /* ... */ }, }, }, // ...});
Transition side-effects receive a single parameter containing the machine’s current state
, the current event
, and a send()
function, which can be used to send events to the machine instance.