State machine with context

We mentioned before that an actor stores its own state. A state machine is no different.

In fact, a state machine can define its own context object.

In this lesson we are going to learn context and actions to implement the same toggle logic as before.

State machine context

Let's start back from our empty state machine:

import { setup } from "xstate";

const machine = setup({}).createMachine({});

The context type is defined inside setup/context:

Context in XState must be an object, we cannot store a boolean directly.

import { setup } from "xstate";

type Context = { toggleValue: boolean }; // 👈 Context (object)

const machine = setup({
  types: {
    context: {} as Context,
  },
}).createMachine({});

You will now notice a type error inside createMachine:

Property 'context' is missing in type '{}' but required in type [...]

We defined the context type, but we did not provide a valid initial value inside createMachine.
We defined the context type, but we did not provide a valid initial value inside createMachine.

That's because we haven't defined the initial context value. We do that by adding context inside createMachine:

import { setup } from "xstate";

type Context = { toggleValue: boolean };
const initialContext: Context = { toggleValue: false };

const machine = setup({
  types: {
    context: {} as Context,
  },
}).createMachine({
  context: initialContext,
});

States and initial state are required

Keep in mind: a state machine always requires at least one state.

Therefore, we always need to define states and initial. We add a "Idle" state as placeholder:

import { setup } from "xstate";

type Context = { toggleValue: boolean };
const initialContext: Context = { toggleValue: false };

const machine = setup({
  types: {
    context: {} as Context,
  },
}).createMachine({
  context: initialContext,
  initial: "Idle",
  states: {
    Idle: {},
  },
});