9.4 KiB
XState v5 Core API Reference
Machine Creation
createMachine(config)
Creates a state machine configuration.
import { createMachine } from 'xstate';
const machine = createMachine({
id: 'machineId', // Unique identifier
initial: 'stateName', // Initial state
context: {}, // Initial context data
types: {}, // TypeScript type definitions
states: {}, // State definitions
on: {}, // Global transitions
entry: [], // Entry actions
exit: [], // Exit actions
after: {}, // Delayed transitions
always: [], // Eventless transitions
invoke: {}, // Invoked services
tags: [], // State tags
description: '', // Machine description
});
setup(config)
Configures reusable machine logic with strong typing.
import { setup } from 'xstate';
const machine = setup({
types: {
context: {} as ContextType,
events: {} as EventType,
input: {} as InputType,
output: {} as OutputType,
},
actions: {
// Named action implementations
actionName: (context, event, meta) => {
/* ... */
},
},
guards: {
// Named guard implementations
guardName: (context, event, meta) => boolean,
},
actors: {
// Actor logic definitions
actorName: fromPromise(() => fetch('/api')),
},
delays: {
// Named delay functions
delayName: (context, event) => 1000,
},
}).createMachine({
// Machine configuration
});
Actor Creation and Management
createActor(logic, options?)
Creates an actor instance from machine or actor logic.
const actor = createActor(machine, {
id: 'actorId', // Actor identifier
input: {}, // Initial input
snapshot: {}, // Restored snapshot
systemId: 'systemId', // Actor system ID
logger: console.log, // Custom logger
inspect: (event) => {}, // Inspection handler
});
Actor Methods
// Lifecycle
actor.start(); // Start the actor
actor.stop(); // Stop the actor
actor.getSnapshot(); // Get current snapshot
actor.getPersistedSnapshot(); // Get persistable snapshot
// Communication
actor.send(event); // Send an event
actor.send({ type: 'EVENT' }); // Send event object
// Subscription
const subscription = actor.subscribe(observer);
subscription.unsubscribe();
// System
actor.system; // Access actor system
State Configuration
State Node Properties
{
type: 'atomic' | 'compound' | 'parallel' | 'final' | 'history',
initial: 'childStateName', // For compound states
context: {}, // State-specific context
states: {}, // Child states
on: {}, // Transitions
entry: [], // Entry actions
exit: [], // Exit actions
always: [], // Eventless transitions
after: {}, // Delayed transitions
invoke: {}, // Invoked services
tags: [], // State tags
description: '', // State description
meta: {}, // Metadata
history: 'shallow' | 'deep', // For history states
}
Transition Configuration
{
target: 'stateName' | ['state1', 'state2'], // Target state(s)
guard: 'guardName' | guardFunction, // Condition
actions: ['action1', 'action2'], // Actions to execute
reenter: boolean, // Re-enter state
description: 'Transition description', // Documentation
}
Actions
assign(assignment)
Updates machine context immutably.
// Function updater
assign({
count: ({ context }) => context.count + 1,
user: ({ context, event }) => event.user,
});
// Object updater
assign({ count: 5, user: null });
// Single property
assign(({ context }) => ({
...context,
modified: true,
}));
raise(event)
Raises an event internally.
raise({ type: 'INTERNAL_EVENT' });
raise(({ context }) => ({
type: 'DYNAMIC_EVENT',
data: context.someValue,
}));
sendTo(actor, event)
Sends event to another actor.
sendTo('actorId', { type: 'MESSAGE' });
sendTo(({ context }) => context.someActor, { type: 'EVENT' });
emit(event)
Emits an event to parent actor.
emit({ type: 'CHILD_EVENT', data: value });
log(message)
Logs a message (for debugging).
log('State entered');
log(({ context }) => `Count: ${context.count}`);
stop(actorId)
Stops a spawned actor.
stop('childActorId');
cancel(sendId)
Cancels a delayed send.
cancel('delayedSendId');
enqueueActions(callback)
Enqueues actions conditionally at runtime. Replaces v4's pure() and choose().
import { enqueueActions } from 'xstate';
// Basic conditional actions
entry: enqueueActions(({ context, event, enqueue, check }) => {
// Conditionally enqueue actions
if (context.count > 0) {
enqueue('logPositive');
}
// Use check() for guards
if (check({ type: 'hasPermission' })) {
enqueue('performSecureAction');
}
// Enqueue multiple actions
enqueue([
{ type: 'log', params: { message: 'Processing' } },
'processData',
assign({ processing: true }),
]);
});
// With parameters
enqueueActions(({ context, enqueue }, params: { threshold: number }) => {
if (context.value > params.threshold) {
enqueue('handleHighValue');
}
});
Guards
Guard Functions
// Inline guard
guard: ({ context, event }) => context.count > 0;
// Named guard
guard: 'isValid';
// Negated guard
guard: not('isInvalid');
// Combined guards
guard: and(['isValid', 'isAuthorized']);
guard: or(['isAdmin', 'isOwner']);
Guard Helpers
import { not, and, or, stateIn } from 'xstate';
not(guard); // Negates a guard
and([guard1, guard2]); // All must be true
or([guard1, guard2]); // At least one must be true
stateIn('state.path'); // Checks if in state
Invoked Services
Service Configuration
invoke: {
id: 'serviceId',
src: 'serviceName' | actorLogic,
input: ({ context, event }) => ({}),
onDone: {
target: 'success',
actions: assign({ data: ({ event }) => event.output }),
},
onError: {
target: 'failure',
actions: assign({ error: ({ event }) => event.error }),
},
onSnapshot: {
actions: ({ event }) => console.log(event.snapshot),
},
}
Multiple Invocations
invoke: [
{ id: 'service1', src: 'api1' },
{ id: 'service2', src: 'api2' },
];
Spawning Actors
spawn(logic, options?)
Spawns a child actor.
import { spawn } from 'xstate';
// In an action
spawn(childMachine, {
id: 'childId',
systemId: 'childSystem',
input: { initial: 'data' },
syncSnapshot: true,
});
stopChild(actorId)
Stops a spawned child actor.
stopChild('childId');
Delayed Transitions
After Configuration
after: {
1000: 'timeout', // Fixed delay
DELAY_NAME: 'delayed', // Named delay
[({ context }) => context.delay]: 'dynamic', // Dynamic delay
}
Eventless Transitions
Always Configuration
always: [
{ target: 'state1', guard: 'condition1' },
{ target: 'state2', guard: 'condition2' },
{ target: 'default' }, // Fallback
];
Utility Functions
waitFor(actor, predicate, options?)
Waits for an actor to reach a specific condition.
const snapshot = await waitFor(actor, (snapshot) => snapshot.matches('done'), {
timeout: 5000,
});
toPromise(actor)
Converts an actor to a Promise.
const result = await toPromise(actor);
createEmptyActor()
Creates an actor that does nothing.
const emptyActor = createEmptyActor();
Type Helpers
ActorRefFrom<T>
Gets the ActorRef type from logic.
type MyActorRef = ActorRefFrom<typeof machine>;
SnapshotFrom<T>
Gets the Snapshot type from logic or ActorRef.
type MySnapshot = SnapshotFrom<typeof machine>;
EventFromLogic<T>
Gets the event union type from logic.
type MyEvents = EventFromLogic<typeof machine>;
StateValueFrom<T>
Gets the state value type from logic.
type MyStateValue = StateValueFrom<typeof machine>;
ContextFrom<T>
Gets the context type from logic.
type MyContext = ContextFrom<typeof machine>;
Inspection and Debugging
Inspector API
const actor = createActor(machine, {
inspect: (inspectionEvent) => {
if (inspectionEvent.type === '@xstate.snapshot') {
console.log('Snapshot:', inspectionEvent.snapshot);
}
},
});
Inspection Event Types
@xstate.actor- Actor created/stopped@xstate.snapshot- Snapshot updated@xstate.event- Event processed@xstate.microstep- Microstep taken
State Methods
state.matches(stateValue)
Checks if in a specific state.
if (state.matches('loading')) {
/* ... */
}
if (state.matches({ form: 'valid' })) {
/* ... */
}
state.hasTag(tag)
Checks if state has a tag.
if (state.hasTag('loading')) {
/* ... */
}
state.can(event)
Checks if an event can cause a transition.
if (state.can({ type: 'SUBMIT' })) {
/* ... */
}
state.nextEvents
Gets available events from current state.
const events = state.nextEvents; // ['SUBMIT', 'CANCEL']