Xstate: transitioning in actions

Created on 12 Nov 2018  路  3Comments  路  Source: davidkpiano/xstate

Guidance

I've been looking through the docs & can't find any examples of calling a transition from an action. Example, if an action contacts a server for a user to sign in, I'd want to transition to ethier signedIn or error state based on the response:

const signInMachine = Machine({
  id: 'signIn',
  initial: 'dataEntry',
  strict: true,
  states: {
    dataEntry: {
      on: { 
        SUBMIT: {
          target: 'awaitingResponse',
          actions: ['contactService']
        }
      }
    },
    awaitingResponse: {
      on: {
        SUCCESS: 'signedIn',
        FAIL: 'error'
      }
    },
    signedIn: {},
    error: {}
  }
}, {
  actions: {
    contactService: (ctx, evt) => {
      myContactServerFunc()
        .then(() => transition to signedIn state)
        .catch(() => transition to error state)
    }
  }
})

I have seen examples of pulling out a send method from the library:

import { Machine, actions } from 'xstate'
const { send } = actions;

However this does not work.

documentation invalid question

Most helpful comment

By the way, you can also write it in a JSON-compatible format:

invoke: {
  src: 'contactServer',
  onDone: 'signedIn',
  onError: 'error'
},
// ...

// second argument to Machine()
{
  services: {
    contactServer: (ctx, event) => myContactServerFunc()
  }
}

All 3 comments

Right, actions are the wrong approach for this. When you execute an action, it should be considered _fire and forget_; in other words, it's a side-effect that does not affect the state of the machine.

Instead, what you want is to invoke a service, since this offers a "...more tightly coupled form of communication" with the parent statechart (see https://www.w3.org/TR/scxml/#ExternalIntroduction for info regarding <invoke> in the SCXML spec).

For your example (and I'll add this to the docs), it would be:

dataEntry: {
  on: {
    SUBMIT: 'awaitingResponse'
  }
},
awaitingResponse: {
  invoke: {
    // function that returns a promise
    src: (ctx, event) => myContactServerFunc(),
    onDone: 'signedIn', // .then(), resolved
    onError: 'error'    // .catch(), rejected
  }
},
signedIn: {},
error: {}

This is working in master and will be out in the next release.

By the way, you can also write it in a JSON-compatible format:

invoke: {
  src: 'contactServer',
  onDone: 'signedIn',
  onError: 'error'
},
// ...

// second argument to Machine()
{
  services: {
    contactServer: (ctx, event) => myContactServerFunc()
  }
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

kurtmilam picture kurtmilam  路  3Comments

suku-h picture suku-h  路  3Comments

3plusalpha picture 3plusalpha  路  3Comments

mattiamanzati picture mattiamanzati  路  3Comments

greggman picture greggman  路  3Comments