Callbacks
Promise actors let you model promises declaratively but not every actor will be a promise. Callback actors give you a flexible API for managing a long-running actor that can do several things a promise can’t, like:
- Send events back to its parent
- Receive events from its parent and react to them
- Start listeners/processes and clean them up when needed
Callback actors are declared using the () => () => {}
syntax, which is how XState distinguishes them from promise actors, which are declared as: () => {}
.
import { createMachine } from 'xstate';
createMachine(
{
invoke: {
src: 'callbackActor',
},
},
{
// `actors` in v5
services: {
callbackActor: (context, event) => (sendBack, onReceive) => {
// Run any code you want inside here
return () => {
// Any code inside here will be called when
// you leave this state, or the machine is stopped
};
},
},
}
);
Callbacks are called with:
context
, the state of the context at the moment the actor started.event
, the last event sent to the machine.
Callbacks also receive a sendBack
function, which you can use to send events back to its parent machine.
import { createMachine } from 'xstate';
createMachine(
{
initial: 'counting',
states: {
counting: {
invoke: {
src: 'callbackActor',
},
on: {
ONE_SECOND_PASSED: {
actions: 'logToConsole',
},
STOP_COUNTING: {
target: 'stopped',
},
},
},
stopped: {
type: 'final',
},
},
},
{
actions: {
logToConsole: () => {
console.log('One second passed!');
},
},
// `actors` in v5
services: {
callbackActor: (context, event) => (sendBack, onReceive) => {
const interval = setInterval(() => {
sendBack({
type: 'ONE_SECOND_PASSED',
});
}, 1000);
return () => {
clearInterval(interval);
};
},
},
}
);
In the example above, we use sendBack
to send an event back to the parent machine every second.
We can return a function from the callback actor to run any necessary “cleanup.” This cleanup function is run when the state containing the invoke is exited. In the example above, the interval is cleared when the counting
state is exited.