:::warning These XState v4 docs are no longer maintained
XState v5 is out now! Read more about XState v5
🆕 Find more about creating machines using XState in our new docs. :::
A state machine is a finite set of states that can transition to each other deterministically due to events. To learn more, read our introduction to statecharts.
State machines and statecharts alike are defined using the createMachine()
factory function:
import { createMachine } from 'xstate';
const lightMachine = createMachine({
// Machine identifier
id: 'light',
// Initial state
initial: 'green',
// Local context for entire machine
context: {
elapsed: 0,
direction: 'east'
},
// State definitions
states: {
green: {
/* ... */
},
yellow: {
/* ... */
},
red: {
/* ... */
}
}
});
The machine config is the same as the state node config, with the addition of the context property:
context
- represents the local "extended state" for all of the machine's nested states. See the docs for context for more details.
Implementations for actions, delays, guards, and services can be referenced in the machine config as a string, and then specified as an object in the 2nd argument to createMachine()
:
const lightMachine = createMachine(
{
id: 'light',
initial: 'green',
states: {
green: {
// action referenced via string
entry: 'alertGreen'
}
}
},
{
actions: {
// action implementation
alertGreen: (context, event) => {
alert('Green!');
}
},
delays: {
/* ... */
},
guards: {
/* ... */
},
services: {
/* ... */
}
}
);
This object has 5 optional properties:
actions
- the mapping of action names to their implementationdelays
- the mapping of delay names to their implementationguards
- the mapping of transition guard (cond
) names to their implementationservices
- the mapping of invoked service (src
) names to their implementationactivities
(deprecated) - the mapping of activity names to their implementation
Existing machines can be extended using .withConfig()
, which takes the same object structure as above:
const lightMachine = // (same as above example)
const noAlertLightMachine = lightMachine.withConfig({
actions: {
alertGreen: (context, event) => {
console.log('green');
}
}
});
As shown in the first example, the context
is defined directly in the configuration itself. If you want to extend an existing machine with a different initial context
, you can use .withContext()
and pass in the custom context
:
const lightMachine = // (same as first example)
const testLightMachine = lightMachine.withContext({
elapsed: 1000,
direction: 'north'
});
::: warning
This will not do a shallow merge of the original context
, and will instead replace the original context
with the context
provided to .withContext(...)
. You can still "merge" contexts manually, by referencing machine.context
:
const testLightMachine = lightMachine.withContext({
// merge with original context
...lightMachine.context,
elapsed: 1000
});
:::