Systems
An actor system is a collection of actors that can communicate with each other. Actors can invoke/spawn other actors, which forms a natural hierarchy of actors that belong to the same system.
In XState, a system is implicitly created from the root actor, which is the actor that is returned from createActor(machine).start()
. The system can be accessed from the actor.system
property of actors, and from the destructured { system }
property from state machine actions:
import { createMachine, createActor } from 'xstate';
const machine = createMachine({
entry: ({ system }) => {
// ...
},
});
const actor = createActor(machine).start();
actor.system;
The root of a system can also be explicitly assigned a systemId
in the createActor(...)
function:
import { createActor } from 'xstate';
const actor = createActor(machine, {
systemId: 'root-id',
});
actor.start();
This is useful for actors in the system to be able send events to the root actor.
Actor registration​
Actors can be registered with the system so that any other actor in the system can obtain a reference to it.
Invoked actors are registered with a system-wide systemId
in the invoke
object:
import { createMachine, createActor, sendTo } from 'xstate';
const formMachine = createMachine({
// ...
on: {
submit: {
actions: sendTo(({ system }) => system.get('notifier'), {
type: 'notify',
message: 'Form submitted!',
}),
},
},
});
const feedbackMachine = createMachine({
invoke: {
systemId: 'formMachine',
src: formMachine,
},
// ...
states: {
// ...
form: {
invoke: formMachine,
},
},
});
const feedbackActor = createActor(feedbackMachine).start();
Spawned actors are registered with a system-wide systemId
in the 2nd argument of the spawn
function:
import { createMachine, createActor, assign } from 'xstate';
const todoMachine = createMachine({
// ...
});
const todosMachine = createMachine({
// ...
on: {
'todo.add': {
actions: assign({
todos: ({ context, spawn }) => {
const newTodo = spawn(todoMachine, {
systemId: `todo-${context.todos.length}`,
});
return context.todos.concat(newTodo);
},
}),
},
},
});
Actor communication​
You can also reference a specific actor from the system using system.get('actorId')
:
Stopping a system​
- Stop from root actor:
actor.stop()
- Cannot stop from descendant actors
- Warning will be logged
Systems and TypeScript​
invoke.systemId
spawn(thing, { systemId })
system.get('actorId')
rootActor.stop()
System cheatsheet​
Cheatsheet: actor system​
import { createMachine, createActor } from 'xstate';
const machine = createMachine({
entry: ({ system }) => {
// ...
},
});
const actor = createActor(machine).start();
actor.system;
Cheatsheet: explicitly assign a systemId
​
import { createActor } from 'xstate';
const actor = createActor(machine, {
systemId: 'root-id',
});
actor.start();
Cheatsheet: register an invoked actor with the system​
import { createMachine, createActor, sendTo } from 'xstate';
const formMachine = createMachine({
// ...
on: {
submit: {
actions: sendTo(({ system }) => system.get('notifier'), {
type: 'notify',
message: 'Form submitted!',
}),
},
},
});
const feedbackMachine = createMachine({
invoke: {
systemId: 'formMachine',
src: formMachine,
},
// ...
states: {
// ...
form: {
invoke: formMachine,
},
},
});
const feedbackActor = createActor(feedbackMachine).start();
Cheatsheet: register a spawned actor with the system​
import { createMachine, createActor, assign } from 'xstate';
const todoMachine = createMachine({
// ...
});
const todosMachine = createMachine({
// ...
on: {
'todo.add': {
actions: assign({
todos: ({ context, spawn }) => {
const newTodo = spawn(todoMachine, {
systemId: `todo-${context.todos.length}`,
});
return context.todos.concat(newTodo);
},
}),
},
},
});