# Sequence

These XState v4 docs are no longer maintained

XState v5 is out now! Read more about XState v5 (opens new window) and check out the XState v5 docs (opens new window).

A sequence are a number of steps that happen in a specific order, and one at a time. This can be modeled with a state machine:

const stepMachine = createMachine({
  id: 'step',
  initial: 'one',
  states: {
    one: {
      on: { NEXT: 'two' }
    },
    two: {
      on: { NEXT: 'three', PREV: 'one' }
    },
    three: {
      type: 'final'
    }
  }
});

console.log(stepMachine.transition('one', { type: 'NEXT' }).value);
// => 'two'

In this example, the machine is in the steps 'one', 'two', or 'three', and transitions between them in that order on the 'NEXT' event, until it reaches the last step. The 'PREV' event is optional, and allows the machine to go to a previous step.

Modeling the final step of the sequence as a final state with { type: 'final' } makes it easier for the machine to be invoked by another machine, or used as a child machine of a bigger machine, since onDone can be defined on the parent machine as a transition when the sequence machine reaches its final state.

# Async Sequences

Sometimes, many async (e.g., Promise-based) operations need to occur in sequence. This can be modeled similarly by invoking the services in sequence:

// Returns a Promise, e.g.:
// {
//   id: 42,
//   name: 'David',
//   friends: [2, 3, 5, 7, 9] // friend IDs
// }
function getUserInfo(context) {
  return fetch(`/api/users/${context.userId}`).then((response) =>
    response.json()
  );
}

// Returns a Promise
function getUserFriends(context) {
  const { friends } = context.user;

  return Promise.all(
    friends.map((friendId) =>
      fetch(`/api/users/${friendId}/`).then((response) => response.json())
    )
  );
}

const friendsMachine = createMachine({
  id: 'friends',
  context: { userId: 42, user: undefined, friends: undefined },
  initial: 'gettingUser',
  states: {
    gettingUser: {
      invoke: {
        src: getUserInfo,
        onDone: {
          target: 'gettingFriends',
          actions: assign({
            user: (context, event) => event.data
          })
        }
      }
    },
    gettingFriends: {
      invoke: {
        src: getUserFriends,
        onDone: {
          target: 'success',
          actions: assign({
            friends: (context, event) => event.data
          })
        }
      }
    },
    success: {
      type: 'final'
    }
  }
});
Last Updated: 2/29/2024, 12:17:17 PM