Skip to content

Latest commit

 

History

History
180 lines (166 loc) · 4.57 KB

File metadata and controls

180 lines (166 loc) · 4.57 KB

Creating the Counter state machine

View the Visualization. See the index.test.tsx file for examples of use.

Calling createCounterMachineConfig thus:

createCounterMachineConfig({
  count: 10,                 // defaults to 0; you can set the starting count
  enabledEvents: [
    "COUNTER_DECREMENT",
    "COUNTER_INCREMENT",
    "COUNTER_RESET"
  ],                         // will publish to event bus on these transitions
  id: "my-counter",          // defaults to generateShortId; should be unique
  increment: 5,              // defaults to 1; you can set the increment
  initial: "counterPaused",  // defaults to "counting"
  otherOption: "whatever",   // any other key-value pairs are simply passed to the context
  topic: "counter",          // used by the publishCounterEvent action
})

Returns this:

{
  machine:   {
    context: {
      count: 10,
      enabledEvents: [
        "COUNTER_DECREMENT",
        "COUNTER_INCREMENT",
        "COUNTER_RESET"
      ],
      increment: 5,
      otherOption: "whatever",
      topic: "counter",
      transitions: 0,
    },
    id: "my-counter",
    initial: "counterPaused",
    states: {
      counting: {
        on: {
          COUNTER_CLEAR: {
            actions: [
              "clear",
              "publishCounterEvent"
            ],
            target: "counting",
            internal: true
          },
          COUNTER_DECREMENT: {
            actions: [
              "decrement",
              "publishCounterEvent"
            ],
            target: "counting",
            internal: true
          },
          COUNTER_INCREMENT: {
            actions: [
              "increment",
              "publishCounterEvent"
            ],
            target: "counting",
            internal: true
          },
          COUNTER_PAUSE: {
            actions: [
              "publishCounterEvent"
            ],
            target: "counterPaused"
          },
          COUNTER_RESET: {
            actions: [
              "reset",
              "publishCounterEvent"
            ],
            target: "counting",
            internal: true
          },
          COUNTER_STOP: {
            actions: [
              "publishCounterEvent"
            ],
            target: "counterDone"
          }
        }
      },
      counterPaused: {
        on: {
          COUNTER_CLEAR: {
            actions: [
              "clear",
              "publishCounterEvent"
            ]
          },
          COUNTER_STOP: {
            actions: [
              "publishCounterEvent"
            ],
            target: "counterDone"
          },
          COUNTER_RESUME: {
            actions: [
              "publishCounterEvent"
            ],
            target: "counting",
            internal: true
          },
          COUNTER_RESET: {
            actions: [
              "reset",
              "publishCounterEvent"
            ],
            target: "counting",
            internal: true
          }
        }
      },
      counterDone: {
        type: "final"
      }
    },
    actions: {
      clear: assign({
        count: (_) => 0,
        transitions: (context) => context.transitions + 1,
      }),
      decrement: assign({
        count: (context) => context.count - context.increment,
        transitions: (context) => context.transitions + 1,
      }),
      increment: assign({
        count: (context) => context.count + context.increment,
        transitions: (context) => context.transitions + 1,
      }),
      publishCounterEvent: (context, event) => {
        const { enabledEvents = [], topic, ...rest } = context;

        if (enabledEvents.includes(event.type)) {
          publish(
            { eventName: event.type, data: { ...rest } },
            { topic: topic }
          );
        }
      },
      reset: assign({
        count: (_) => 0,
        transitions: (_) => 0,
      }),
    },
  }
}

The optional enabledEvents determines which transitions will publish events to the Event Bus. Possible transitions include:

  • COUNTER_CLEAR
  • COUNTER_DECREMENT
  • COUNTER_INCREMENT
  • COUNTER_PAUSE
  • COUNTER_RESET
  • COUNTER_RESUME
  • COUNTER_STOP

The above be passed to XState's createMachine function by separating the machine from the actions:

const { machine, actions } = createCounterMachineConfig()

const animationStateMachine = createMachine(machine, { actions })

But see useMachines for how this is meant to be used with React and a configuration object.

Here is the machine as seen by the visualizer:

Counter Machine Visualization