Skip to content

Flat Lifecycle Hooks API

The transitionHooks function provides a flat, composable API for registering lifecycle hooks on a FactoryMachine. Each hook config can specify matching criteria (from, to, type) and any lifecycle phase (effect, before, after, guard, etc.).

TypeScript Friendly: All handlers are fully typed, with autocompletion for state/event keys and hook phases.

Each entry to transitionHooks is an object with optional from, to, type keys for matching, and one or more lifecycle hook functions:

transitionHooks(
{ from: "Idle", type: "start", to: "Running", effect: fn, before, after },
{ from: "Idle", enter: fn, leave: fn },
{ type: "resolve", guard: e => true },
{ effect: globalFn }
)

You can use wildcards by omitting keys.

setup(machine)(
transitionHooks(
{ from: "Idle", type: "start", to: "Running", effect: fn, before, after },
{ from: "Idle", enter: fn, leave: fn },
{ type: "resolve", guard: e => true },
{ effect: globalFn }
)
);

Comparison: transitionHooks vs onLifecycle vs Functional Enhancers

Section titled “Comparison: transitionHooks vs onLifecycle vs Functional Enhancers”
FeatureonLifecycle (Config Object)transitionHooks (Flat API)Functional Enhancers (effect(whenEvent(...)), etc.)
StructureNested, grouped by state/eventFlat, composable, per hookPure, composable, per enhancer
ModularityAll-in-one configSplit across files/modulesSplit, highly modular, functional
ReadabilityGood for grouped logicGood for scanning hooksGood for functional composition
Type SafetyStrongStrongStrong
Wildcards”*” keysOmit keysPredicate/wildcard via when/whenEvent
Use CaseComplex, grouped logicModular, scattered logicFunctional, advanced composition

Choose onLifecycle for grouped, declarative logic.
Choose transitionHooks for modular, flat, and composable logic.
Choose functional enhancers for pure, highly composable, and advanced functional patterns.

setup(machine)(
transitionHooks(
{ from: "Idle", type: "start", to: "Running", effect: fn, before, after },
{ from: "Idle", enter: fn, leave: fn },
{ type: "resolve", guard: e => true },
{ effect: globalFn },
{ type: "tick", effect: tickEffect },
{ type: "stop", effect: stopEffect },
{ effect: (ev) => console.log(ev) } // global
)
);

You can also choose a more pure functional approach using raw transition hook method enhancers:

setup(machine)(
enter(fn),
guard(fn),
leave(fn),
handle(fn),
// ...other enhancers
)

This style is ideal for highly modular or functional codebases, and can be mixed with transitionHooks or other enhancers.

For modular apps, split hooks across files and import them:

setup(machine)(
...allEnhancers,
transitionHooks(...importedHooks)
)