# Machines

A state machine is a finite set of states that can transition to each other deterministically due to events. To learn more, read our introduction to statecharts.

# Configuration

State machines and statecharts alike are defined using the createMachine() factory function:

import { createMachine } from 'xstate';

const lightMachine = createMachine({
  // Machine identifier
  id: 'light',

  // Initial state
  initial: 'green',

  // Local context for entire machine
  context: {
    elapsed: 0,
    direction: 'east'
  },

  // State definitions
  states: {
    green: {
      /* ... */
    },
    yellow: {
      /* ... */
    },
    red: {
      /* ... */
    }
  }
});

The machine config is the same as the state node config, with the addition of the context property:

  • context - represents the local "extended state" for all of the machine's nested states. See the docs for context for more details.

# Options

Implementations for actions, delays, guards, and services can be referenced in the machine config as a string, and then specified as an object in the 2nd argument to createMachine():

const lightMachine = createMachine(
  {
    id: 'light',
    initial: 'green',
    states: {
      green: {
        // action referenced via string
        entry: 'alertGreen'
      }
    }
  },
  {
    actions: {
      // action implementation
      alertGreen: (context, event) => {
        alert('Green!');
      }
    },
    delays: {
      /* ... */
    },
    guards: {
      /* ... */
    },
    services: {
      /* ... */
    }
  }
);

This object has 5 optional properties:

  • actions - the mapping of action names to their implementation
  • delays - the mapping of delay names to their implementation
  • guards - the mapping of transition guard (cond) names to their implementation
  • services - the mapping of invoked service (src) names to their implementation
  • activities (deprecated) - the mapping of activity names to their implementation

# Extending Machines

Existing machines can be extended using .withConfig(), which takes the same object structure as above:

const lightMachine = // (same as above example)

const noAlertLightMachine = lightMachine.withConfig({
  actions: {
    alertGreen: (context, event) => {
      console.log('green');
    }
  }
});

# Initial Context

As shown in the first example, the context is defined directly in the configuration itself. If you want to extend an existing machine with a different initial context, you can use .withContext() and pass in the custom context:

const lightMachine = // (same as first example)

const testLightMachine = lightMachine.withContext({
  elapsed: 1000,
  direction: 'north'
});

WARNING

This will not do a shallow merge of the original context, and will instead replace the original context with the context provided to .withContext(...). You can still "merge" contexts manually, by referencing machine.context:

const testLightMachine = lightMachine.withContext({
  // merge with original context
  ...lightMachine.context,
  elapsed: 1000
});