A MachineSnapshot (also called State) represents the state of a state machine actor at a specific point in time. It contains the current state value, context, and other metadata.
State snapshots are immutable and represent a point-in-time snapshot of the machine’s state.
Type
type MachineSnapshot<
TContext extends MachineContext,
TEvent extends EventObject,
TChildren extends Record<string, AnyActorRef | undefined>,
TStateValue extends StateValue,
TTag extends string,
TOutput,
TMeta extends MetaObject,
TStateSchema extends StateSchema
> =
| ActiveMachineSnapshot<...>
| DoneMachineSnapshot<...>
| ErrorMachineSnapshot<...>
| StoppedMachineSnapshot<...>
Properties
The current state value.This represents the active state nodes in the state machine:
- For atomic state nodes, it is a string (e.g.,
"idle")
- For compound parent state nodes, it is an object (e.g.,
{ red: "walk" })
// Atomic state
snapshot.value; // => "loading"
// Nested states
snapshot.value; // => { red: "walk" }
status
'active' | 'done' | 'error' | 'stopped'
The current status of the snapshot.
'active' - The machine is running normally
'done' - The machine has reached a top-level final state
'error' - The machine encountered an error
'stopped' - The machine has been stopped
The current context (extended state) of the machine.snapshot.context; // => { count: 42, user: {...} }
The output data produced when the machine reaches a top-level final state.Only available when status is 'done'.if (snapshot.status === 'done') {
console.log(snapshot.output);
}
The error that caused the machine to enter an error state.Only available when status is 'error'.if (snapshot.status === 'error') {
console.error(snapshot.error);
}
The tags of the active state nodes that represent the current state value.if (snapshot.tags.has('loading')) {
// Show loading indicator
}
The state machine that produced this state snapshot.
An object mapping actor IDs to spawned/invoked actors.const childActor = snapshot.children.myChild;
The history value of the state, used for history states.
Methods
matches
(stateValue: StateValue) => boolean
Determines whether the current state value is a subset of the given partial state value.if (snapshot.matches('loading')) {
// In the 'loading' state
}
if (snapshot.matches({ form: 'valid' })) {
// In the 'form.valid' state
}
Parameters:
stateValue - The state value to match against
Returns: true if the current state matches, false otherwise
Determines whether the current state has a specific tag.if (snapshot.hasTag('loading')) {
// Current state is tagged with 'loading'
}
Parameters:
tag - The tag to check for
Returns: true if any active state node has the tag, false otherwise
can
(event: Event) => boolean
Determines whether sending the event will cause a non-forbidden transition to be selected.if (snapshot.can({ type: 'SUBMIT' })) {
// The SUBMIT event can be handled
}
Parameters:
event - The event to test
Returns: true if the event will cause a transition, false otherwise
getMeta
() => Record<string, any>
Returns the meta data of all active state nodes.const meta = snapshot.getMeta();
// => { 'loading': { message: 'Loading...' } }
Returns: An object mapping state node IDs to their meta data
Returns a JSON-serializable representation of the snapshot.const json = snapshot.toJSON();
Returns: A plain object representation of the snapshot
Examples
Checking state values
import { createMachine, createActor } from 'xstate';
const machine = createMachine({
initial: 'idle',
states: {
idle: {
on: { START: 'running' }
},
running: {
on: { STOP: 'idle' }
}
}
});
const actor = createActor(machine);
actor.start();
const snapshot = actor.getSnapshot();
if (snapshot.matches('idle')) {
console.log('Currently idle');
}
console.log(snapshot.value); // 'idle'
Using context
import { createMachine, createActor, assign } from 'xstate';
const counterMachine = createMachine({
context: { count: 0 },
initial: 'active',
states: {
active: {
on: {
INCREMENT: {
actions: assign({
count: ({ context }) => context.count + 1
})
}
}
}
}
});
const actor = createActor(counterMachine);
actor.start();
actor.send({ type: 'INCREMENT' });
const snapshot = actor.getSnapshot();
console.log(snapshot.context.count); // 1
import { createMachine, createActor } from 'xstate';
const machine = createMachine({
initial: 'loading',
states: {
loading: {
tags: ['busy'],
on: { SUCCESS: 'success' }
},
success: {
tags: ['complete']
}
}
});
const actor = createActor(machine);
actor.start();
const snapshot = actor.getSnapshot();
if (snapshot.hasTag('busy')) {
console.log('Machine is busy');
}
console.log([...snapshot.tags]); // ['busy']
Checking if events can be handled
import { createMachine, createActor } from 'xstate';
const machine = createMachine({
initial: 'idle',
states: {
idle: {
on: { START: 'running' }
},
running: {
on: { STOP: 'idle' }
}
}
});
const actor = createActor(machine);
actor.start();
const snapshot = actor.getSnapshot();
if (snapshot.can({ type: 'START' })) {
console.log('Can send START event');
actor.send({ type: 'START' });
}
if (!snapshot.can({ type: 'STOP' })) {
console.log('Cannot send STOP event in current state');
}
Working with nested states
import { createMachine, createActor } from 'xstate';
const machine = createMachine({
initial: 'auth',
states: {
auth: {
initial: 'loggedOut',
states: {
loggedOut: {
on: { LOGIN: 'loggedIn' }
},
loggedIn: {}
}
}
}
});
const actor = createActor(machine);
actor.start();
const snapshot = actor.getSnapshot();
console.log(snapshot.value); // { auth: 'loggedOut' }
if (snapshot.matches({ auth: 'loggedOut' })) {
console.log('User is logged out');
}
Accessing child actors
import { createMachine, createActor, fromPromise } from 'xstate';
const childLogic = fromPromise(async () => {
return { data: 'result' };
});
const machine = createMachine({
initial: 'loading',
states: {
loading: {
invoke: {
id: 'dataFetcher',
src: childLogic,
onDone: 'success'
}
},
success: {}
}
});
const actor = createActor(machine);
actor.start();
const snapshot = actor.getSnapshot();
const childActor = snapshot.children.dataFetcher;
if (childActor) {
console.log('Child actor exists:', childActor.id);
}
import { createMachine, createActor } from 'xstate';
const machine = createMachine({
initial: 'loading',
states: {
loading: {
meta: {
message: 'Loading data...'
},
on: { SUCCESS: 'success' }
},
success: {
meta: {
message: 'Data loaded successfully'
}
}
}
});
const actor = createActor(machine);
actor.start();
const snapshot = actor.getSnapshot();
const meta = snapshot.getMeta();
console.log(meta); // { loading: { message: 'Loading data...' } }
See also