Spawn
Sometimes invoking actors may not be flexible enough for your needs. For example, you might want to:
- Invoke child machines that last across several states
- Invoke a dynamic number of actors
You can do this by spawning an actor instead of invoking. Actors created by spawning are spawning actors, and actors created with invoke are invoking actors.
There are two ways to spawn: the spawnChild
action creator, or the spawn
helper function for assign
.
In most cases, prefer spawnChild
, which causes an actor to be spawned, and can accept a configurable ID for the actor to reference it later:
createMachine({
entry: spawnChild(childMachine, {
id: 'child',
}),
});
You can use spawnChild
for multiple spawned actors:
createMachine({
entry: [
spawnChild(childMachine, { id: 'child-1' }),
spawnChild(childMachine, { id: 'child-2' }),
spawnChild(childMachine, { id: 'child-3' }),
],
});
You can also use the spawn
helper function provided by the assign
action creator, which allows you to store a reference to the spawned actor (an ActorRef
) in the machine's context
:
const parentMachine = createMachine({
entry: [
assign({
childMachineRef: ({ spawn }) => spawn(childMachine, { id: 'child' }),
}),
],
});
However, if you use spawn
, make sure you remove the ActorRef from context
to prevent memory leaks when the spawned actor is no longer needed:
actions: [stopChild('child'), assign({ childMachineRef: undefined })];
You can spawn
as many actors as you need:
const childMachine = createMachine({
/* ... */
});
const parentMachine = createMachine({
entry: [
assign({
childMachineRefs: ({ spawn }) => [
spawn(childMachine),
spawn(childMachine),
spawn(childMachine),
],
}),
],
});
If you donβt need to keep track of a reference to the spawned actor (e.g.: for anonymous spawned actors), you can use the spawnChild
action creator. It does not return a reference, but indicates to the XState interpreter that a new actor should be spawned:
createMachine({
entry: spawnChild('workflow', {
id: 'workflow',
}),
});
APIβ
actions: assign({
ref: ({ spawn }) => spawn(fromPromise(...), {
id: 'some-id',
})
})
spawn(actorBehavior, options?)
actorBehavior
- The behavior of the actor to spawn. This can be a function, promise, observable, or callback.options
- Options for spawning the actor.id
(optional) - The ID of the actor. This is used to reference the actor in the state machine.input
(optional) - The input to pass to the actor.systemId
(optional) - A string identifing the actor, unique system-wide.
Sourceβ
- Inline:
spawn(fromPromise(...))
- Referenced:
spawn('getUser')
.provide({ actors })
Lifecycleβ
- Created & started when spawned
- Stopped when the machine is stopped
- Can be manually stopped
Stopping an actorβ
You can stop a child actor via the "stop child" action. This action is created from the stopChild(id)
action creator.
import { setup, stopChild, fromPromise } from 'xstate';
const machine = setup({
actors: {
something: fromPromise(async () => {
// Some actor logic
return 'Some response';
}),
},
}).createMachine({
context: ({ spawn }) => ({
something: spawn('something', { id: 'thing' }),
}),
// ...
on: {
'thing.stop': {
actions: stopChild('thing'),
},
'thing.stopFromContext': {
actions: stopChild(({ context }) => context.something),
},
},
});
Stopping a child actor does not remove it from context
. To remove it from context, use the assign(...)
action creator:
import { setup, stopChild } from 'xstate';
const machine = setup({
// ...
}).createMachine({
context: ({ spawn }) => ({
something: spawn('something', { id: 'thing' }),
}),
// ...
on: {
'thing.stop': {
actions: [stopChild('thing'), assign({ something: undefined })],
},
},
});
Spawn and TypeScriptβ
Coming soon
Spawn cheatsheetβ
Coming soon