Actions vs. actors
Sometimes it’s unclear whether you should use an action or an actor. Both appear to do similar things, executing side effects. Let’s break down the differences:
Actions are “fire-and-forget”; as soon as their execution starts, the statechart running the actions forgets about them. If you specify an action as async
, the action won’t be awaited before moving to the next state. Below is an example:
const machine = createMachine(
{
context: {
userName: '',
},
initial: 'collectingFormDetails',
states: {
collectingFormDetails: {
on: {
SUBMIT: {
actions: 'submitForm',
target: 'submitted',
},
},
},
submitted: {},
},
},
{
actions: {
submitForm: async (context) => {
await createUser(context.userName);
},
},
},
);
You might think that the sequence would work as follows:
- In the
collectingFormDetails
state, we receive theSUBMIT
event. - We execute the
submitForm
action and wait for it to finish. - When the
submitForm
action is done, we go to thesubmitted
state.
Instead, the sequence works like this:
- In the
collectingFormDetails
state, we receive theSUBMIT
event. - We execute the
submitForm
action and immediately transition to thesubmitted
state. - The result of the
submitForm
action is ignored.
To handle submitForm
properly, we need to use an actor:
const machine = createMachine(
{
context: {
userName: '',
},
initial: 'collectingFormDetails',
states: {
collectingFormDetails: {
on: {
SUBMIT: {
target: 'submitting',
},
},
},
submitting: {
invoke: {
src: 'submitForm',
onDone: {
target: 'submitted',
},
onError: {
target: 'errored',
},
},
},
errored: {},
submitted: {},
},
},
{
// `actors` in v5
services: {
submitForm: async (context) => {
await createUser(context.userName);
},
},
},
);
Now, the sequence in the example above is:
- In the
collectingFormDetails
state, we receive theSUBMIT
event. - We go to the
submitting
state, where we execute thesubmitForm
actor. - When the
submitForm
actor is done, we go to thesubmitted
state. - If the
submitForm
actor errors, we go to theerrored
state.
The main difference between actions and actors is that actions can’t communicate back to the machine. Actors can.