# Machines
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.
# Configuration
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.
# Options
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
# Extending Machines
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');
}
}
});
# Initial Context
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
});