Built-in actions
Along with assign, XState has several other built-in actions which can do different things in a state machine. We’ll introduce a couple of built-in actions for now and learn about the others later.
Send action
XState’s built-in send action is useful for when statecharts need to send events back to themselves.
When the send action is executed, it sends an event back to the machine as if it were from an external source.
This pattern can help compose different flows together. In the example below, the user can either press the copy button or press ctrl + c to fire a COPY event to the machine. Using the send action to fire the same event from both actions reduces duplication.
tsimport {createMachine ,send } from "xstate";constkeyboardShortcutMachine =createMachine ({on : {PRESS_COPY_BUTTON : {actions :send ({type : "COPY" }),},PRESS_CTRL_C : {actions :send ({type : "COPY" }),},COPY : {actions : "copyToClipboard",},},});
tsimport {createMachine ,send } from "xstate";constkeyboardShortcutMachine =createMachine ({on : {PRESS_COPY_BUTTON : {actions :send ({type : "COPY" }),},PRESS_CTRL_C : {actions :send ({type : "COPY" }),},COPY : {actions : "copyToClipboard",},},});
You can also dynamically specify the event to send by passing a function to send:
tssend ((context ,event ) => {return {type : "SOME_EVENT",};});
tssend ((context ,event ) => {return {type : "SOME_EVENT",};});
Pure action
The pure action is useful when you need to run a dynamic number of actions depending on the current machine’s state.
pure lets you pass a function to the machine, which calculates the type and number of actions to be executed.
In the example below, we check context to find which actions the machine should run.
tsimport {actions ,createMachine } from "xstate";const {pure } =actions ;createMachine ({context : {runBothActions : false,},entry :pure ((context ) => {if (context .runBothActions ) {// You can return an array of actionsreturn ["action1", "action2"];}// Or a single actionreturn "action1";}),});
tsimport {actions ,createMachine } from "xstate";const {pure } =actions ;createMachine ({context : {runBothActions : false,},entry :pure ((context ) => {if (context .runBothActions ) {// You can return an array of actionsreturn ["action1", "action2"];}// Or a single actionreturn "action1";}),});
Rules of built-in actions
Built-in actions are pure functions. Pure functions don’t execute anything themselves but instead return instructions that tells XState what to do.
For example, the assign function returns an object containing type: 'xstate.assign' and an assigner function.
tsimport {assign } from "xstate";constassignResult =assign ((context ,event ) => ({newValue : true,}));assignResult .type ; // 'xstate.assign'assignResult .assigner ; // (context, event) => ({ newValue: true })
tsimport {assign } from "xstate";constassignResult =assign ((context ,event ) => ({newValue : true,}));assignResult .type ; // 'xstate.assign'assignResult .assigner ; // (context, event) => ({ newValue: true })
The instruction set above is interpreted by XState, which executes the code. The result of assign must be passed directly to actions, entry or exit.
For example, the following code won’t work correctly because the result of the assign isn’t being passed into assignToContext.
tsimport {createMachine ,assign } from "xstate";constmachine =createMachine ({// ...config},{actions : {assignToContext : (context ,event ) => {// 🚫 This won’t work!// The result of the assign isn’t being passed// into assignToContextassign ({message : "Hello!",});},},},);
tsimport {createMachine ,assign } from "xstate";constmachine =createMachine ({// ...config},{actions : {assignToContext : (context ,event ) => {// 🚫 This won’t work!// The result of the assign isn’t being passed// into assignToContextassign ({message : "Hello!",});},},},);
The following example works correctly because the result of the assign is passed into assignToContext:
tsimport {createMachine ,assign } from "xstate";constmachine =createMachine ({// ...config},{actions : {assignToContext :assign ((context ) => ({message : "Hello!",})),},},);
tsimport {createMachine ,assign } from "xstate";constmachine =createMachine ({// ...config},{actions : {assignToContext :assign ((context ) => ({message : "Hello!",})),},},);
Summary
send can be used to send events back to your machine. pure can be used to dynamically return different actions. Built-in actions must be passed directly to the machine or returned from pure.