Executing an action in every state

383 Views Asked by At

I want to execute an action in every state's entry. How can I do that?

It can be done like this:

const promiseMachine = createMachine({
  id: "promise",
  initial: "pending",
  states: {
    pending: {
      entry: ["myAction"]
    },
    resolved: {
      entry: ["myAction"]
    },
    rejected: {
      entry: ["myAction"]
    }
  }
});

However, I have 10+ states, it becomes repetitive to write the same code over and over again.

2

There are 2 best solutions below

0
Steven Spungin On

Iterate config before creating machine.

For example

const config = {
  id: "promise",
  initial: "pending",
  states: {
    pending: {
      entry: []
    },
    resolved: {
      entry: []
    },
    rejected: {
      entry: []
    }
  }
}

Object.values(config.states).forEach(it=>{
  it.entry.push('myAction')
})

createMachine(config);
0
Tobi Obeck On

For every received event you can check on the state instance (docs, old docs) whether a state change did occur. This comes close to performing an action during entry. But I would advise against using such a pattern. It kinda defeats the purpose of using a state machine which is used to precisely define what should happen in each particular state transition.

Example in Svelte:

const { state, send, service } = useMachine(toggleMachine); // for react const [state, send, service]

let oldState = $state.value

service.onTransition((state, event) => {
  if(state.changed && state.value !== oldState){
    // perform some side-effect
    console.log(state.value, state.context)
  }
  oldState = state. Value
});

Alternatively, you can define the machine as type: 'parallel' and have one state with the actual state machine implementation and another with a wildcard transition (docs) for capturing all events that are received. This comes also somewhat close, but triggers for all events! Even events that don't lead to a transition in the actual state machine implementation.

'capturing-all-events': {
  on: {
    "*": {
      internal: true,
      actions: "myAction",
    },
  },
},

Keep in mind there are also utility functions for actions like logging: https://stately.ai/docs/xstate/actions/built-in-actions#log-action