@xstate/fsm¶
XState for Finite State Machines
The @xstate/fsm package contains a minimal, 1kb implementation of XState for finite state machines.
Features¶
@xstate/fsm | XState | |
---|---|---|
Finite states | ✅ | ✅ |
Initial state | ✅ | ✅ |
Transitions (object) | ✅ | ✅ |
Transitions (string target) | ✅ | ✅ |
Delayed transitions | ❌ | ✅ |
Eventless transitions | ❌ | ✅ |
Nested states | ❌ | ✅ |
Parallel states | ❌ | ✅ |
History states | ❌ | ✅ |
Final states | ❌ | ✅ |
Context | ✅ | ✅ |
Entry actions | ✅ | ✅ |
Exit actions | ✅ | ✅ |
Transition actions | ✅ | ✅ |
Parameterized actions | ❌ | ✅ |
Transition guards | ✅ | ✅ |
Parameterized guards | ❌ | ✅ |
Spawned actors | ❌ | ✅ |
Invoked actors | ❌ | ✅ |
- Finite states (non-nested)
- Initial state
- Transitions (object or strings)
- Context
- Entry actions
- Exit actions
- Transition actions
state.changed
If you want to use statechart features such as nested states, parallel states, history states, activities, invoked services, delayed transitions, transient transitions, etc. please use XState
.
Super quick start¶
Installation
1 |
|
Usage (machine):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Usage (service):
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
- Super quick start
- API
createMachine(config)
- Machine config
- State config
- Transition config
- Machine options
- Action config
machine.initialState
machine.transition(state, event)
- State
interpret(machine)
service.subscribe(stateListener)
service.send(event)
service.start()
service.stop()
- TypeScript
- Example
API¶
createMachine(config, options)
¶
Creates a new finite state machine from the config.
Argument | Type | Description |
---|---|---|
config |
object (see below) | The config object for creating the machine. |
options |
object (see below) | The optional options object. |
Returns:
A Machine
, which provides:
machine.initialState
: the machine's resolved initial statemachine.transition(state, event)
: a pure transition function that returns the next state given the currentstate
andevent
The machine config has this schema:
Machine config¶
id
(string) - an identifier for the type of machine this is. Useful for debugging.initial
(string) - the key of the initial state.states
(object) - an object mapping state names (keys) to states
State config¶
on
(object) - an object mapping event types (keys) to transitions
Transition config¶
String syntax:
- (string) - the state name to transition to.
- Same as
{ target: stateName }
Object syntax:
target?
(string) - the state name to transition to.actions?
(Action | Action[]) - the action(s) to execute when this transition is taken.cond?
(Guard) - the condition (predicate function) to test. If it returnstrue
, the transition will be taken.
Machine options¶
actions?
(object) - a lookup object for your string actions.
Action config¶
Function syntax:
- (function) - the action function to execute. Resolves to
{ type: actionFn.name, exec: actionFn }
and the function takes the following arguments: context
(any) - the machine's currentcontext
.event
(object) - the event that caused the action to be executed.
Object syntax:
type
(string) - the action type.exec?
(function) - the action function to execute.
String syntax:
- (string) - the action type.
- By default it resolves to
{ type: actionType, exec: undefined }
. It can resolve to resolved function or resolved object action if the action can be looked up in theoptions.actions
object.
Why use a string or object for defining actions?
Using the string or object syntax is useful for handling actions in a custom way, rather than baking in the implementation details to your machine:1 2 3 4 5 6 |
|
machine.initialState
¶
The resolved initial state of the machine
.
machine.transition(state, event)
¶
A pure transition function that returns the next state given the current state
and event
.
The state can be a string
state name, or a State
object (the return type of machine.transition(...)
).
Argument | Type | Description |
---|---|---|
state |
string or State object |
The current state to transition from |
event |
string or { type: string, ... } |
The event that transitions the current state to the next state |
Returns:
A State
object, which represents the next state.
Example:
1 2 3 4 |
|
State¶
An object that represents the state of a machine with the following schema:
value
(string) - the finite state valuecontext
(object) - the extended state (context)actions
(array) - an array of action objects representing the side-effects (actions) to be executedchanged
(boolean) - whether this state is changed from the previous state (true
if thestate.value
andstate.context
are the same, and there are no side-effects)matches(value)
(boolean) - whether this state's value matches (i.e., is equal to) thevalue
. This is useful for typestate checking.
interpret(machine)
¶
Creates an instance of an interpreted machine, also known as a service. This is a stateful representation of the running machine, which you can subscribe to, send events to, start, and stop.
Actions will also be executed by the interpreter.
Argument | Type | Description |
---|---|---|
machine |
StateMachine | The machine to be interpreted. |
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
service.subscribe(stateListener)
¶
A service (created from interpret(machine)
) can be subscribed to via the .subscribe(...)
method. The subscription will be notified of all state changes (including the initial state) and can be unsubscribed.
Argument | Type | Description |
---|---|---|
stateListener |
(state) => void |
The listener that is called with the interpreted machine's current state whenever it changes. |
Returns:
A subscription object with an unsubscribe
method.
service.send(event)
¶
Sends an event
to the interpreted machine. The event can be a string (e.g., "EVENT"
) or an object with a type
property (e.g., { type: "EVENT" }
).
Argument | Type | Description |
---|---|---|
event |
string or { type: string, ... } |
The event to be sent to the interpreted machine. |
service.start()
¶
Starts the interpreted machine.
Events sent to the interpreted machine will not trigger any transitions until the service is started. All listeners (via service.subscribe(listener)
) will receive the machine.initialState
.
service.stop()
¶
Stops the interpreted machine.
Events sent to a stopped service will no longer trigger any transitions. All listeners (via service.subscribe(listener)
) will be unsubscribed.
TypeScript¶
A machine can be strictly typed by passing in 3 generic types:
TContext
- the machine'scontext
TEvent
- all events that the machine acceptsTState
- all states that the machine can be in
The TContext
type should be an object
that represents all possible combined types of state.context
.
The TEvent
type should be the union of all event objects that the machine can accept, where each event object has a { type: string }
property, as well as any other properties that may be present.
The TState
type should be the union of all typestates (value and contexts) that the machine can be in, where each typestate has:
value
(string) - the value (name) of the statecontext
(object) - an object that extendsTContext
and narrows the shape of the context to what it should be in this state.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
|
Example¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
|