# Getting Started

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).

# Our first machine

Suppose we want to model a Promise (opens new window) as a state machine. First, install XState using NPM or Yarn:

npm install xstate --save

If you're using VSCode, you should install our VSCode Extension (opens new window) to allow you to visualize the machine you're building as you go.

Then, in your project, import createMachine, which is a function that creates a state machine.

import { createMachine } from 'xstate';

const promiseMachine = createMachine(/* ... */);

We'll pass the machine configuration to createMachine. We'll need to provide the:

  • id - to identify the machine
  • initial - to specify the initial state node this machine should be in
  • states - to define each of the child states:
import { createMachine } from 'xstate';

const promiseMachine = createMachine({
  id: 'promise',
  initial: 'pending',
  states: {
    pending: {},
    resolved: {},
    rejected: {}
  }
});

Then, we need to add transitions to the state nodes.

import { createMachine } from 'xstate';

const promiseMachine = createMachine({
  id: 'promise',
  initial: 'pending',
  states: {
    pending: {
      on: {
        RESOLVE: { target: 'resolved' },
        REJECT: { target: 'rejected' }
      }
    },
    resolved: {},
    rejected: {}
  }
});

We'll also need to mark the resolved and rejected state nodes as final state nodes since the promise machine terminates running once it reaches those states:

import { createMachine } from 'xstate';

const promiseMachine = createMachine({
  id: 'promise',
  initial: 'pending',
  states: {
    pending: {
      on: {
        RESOLVE: { target: 'resolved' },
        REJECT: { target: 'rejected' }
      }
    },
    resolved: {
      type: 'final'
    },
    rejected: {
      type: 'final'
    }
  }
});

Our machine is now ready to be visualized. You can copy/paste the code above and visualize it on Stately Viz (opens new window). Here's how it'll look:

# Running our machine

How we run our machine depends on where we're planning to use it.

# In Node/Vanilla JS

To interpret the machine and make it run, we need to add an interpreter. This creates a service:

import { createMachine, interpret } from 'xstate';

const promiseMachine = createMachine({
  /* ... */
});

const promiseService = interpret(promiseMachine).onTransition((state) =>
  console.log(state.value)
);

// Start the service
promiseService.start();
// => 'pending'

promiseService.send({ type: 'RESOLVE' });
// => 'resolved'

# In React

If we wanted to use our machine inside a React component, we could use the useMachine hook:

You'll need to install @xstate/react

import { useMachine } from '@xstate/react';

const Component = () => {
  const [state, send] = useMachine(promiseMachine);

  return (
    <div>
      {/** You can listen to what state the service is in */}
      {state.matches('pending') && <p>Loading...</p>}
      {state.matches('rejected') && <p>Promise Rejected</p>}
      {state.matches('resolved') && <p>Promise Resolved</p>}
      <div>
        {/** You can send events to the running service */}
        <button onClick={() => send('RESOLVE')}>Resolve</button>
        <button onClick={() => send('REJECT')}>Reject</button>
      </div>
    </div>
  );
};
Last Updated: 3/15/2024, 12:45:01 PM