Introduction to Finite State Machines with Xstate and Javascript

ยท

4 min read

Introduction to Finite State Machines  with Xstate and Javascript

Table of Contents

Introduction

A finite state machine (sometimes called a finite state automaton) is a computation model. Finite state machines can be used to model problems in many fields including mathematics, artificial intelligence, games, and linguistics.

A software application can be modeled as a Finite State Machine (FSM) if it can have a finite number of states. Also, the application should be able to transition to another state on an action.

Sounds complicated? Few examples should make it clear!

Motivation

  • Using FSM in your application ensures that your application can never have invalid states!
  • In the web development, it separates the logic and UI. making it easier to test.
  • Read more.

Examples

Let's start with a very simple example.

#1 Bulb

bulb.png

A bulb can have one of the following finite states - on and off. The bulb can transition from the off state to the on state in a turnOn action. Similarly, The bulb can transition from the on state to the off state in a turnOff action. Hence we can model the bulb using an FSM.

This can be implemented in javascript using xstate like. See xstate installation instructions at xstate docs.

  const bulbMachine = Machine({
    initial: "off",
    states: {
      "on": {
        on: {
          "turnOff": "off"
        }
      },
      "off": {
        on: {
          "turnOn": "on"
        }
      }
    }
  });

//  bulbMachine.transition(...) is a pure function and hence doesn't have internal state
// transition(..) takes the current state as first argument and the event name as 2nd one.
const initialState = "off"
const nextState = bulbMachine.transition(initialState, "turnOn").value
console.log(nextState)  // Output: on

// Invalid action, hence no change of state
const state = bulbMachine.transition("on", "turnOn").value
console.log(state) // Output: on

Let's break the above down.

Machine({
 // The initial state of your application.
  initialState: "The initial state",
 // `states` is a object with the expected states of your app as `keys`.
  states: {
       stateName: {
           // `on` is a object with keys as the event name 
           // and the value is the name of the state to transition or action(s).
            on: {
                  "Event_Name": "State_Name_to_transition_to"
            }
       },
  }
})

We have to list all the valid actions that can be taken for each state, which makes sure that invalid actions (actions that are not supposed to happen in the current state) are ignored.

The machine factory Machine({ ... }) returns a stateless machine definition that cannot have an internal state.

// Machine instance with internal state
const bulbService = interpret(bulbMachine)
   // On State transition, this prints the state
  .onTransition((state) => console.log(state.value)) 
  .start(); // Output (initial state): off

bulbService.send('turnOn'); //Output: on

#2 Vending Machine

Vending machines are one of the simplest finite state machines. Let's model a vending machine that only takes the following denominations: 5 and 10.

We can insert coins of the above denominations into the vending machines and it would have a state transition after inserting a coin. The vending machine starts with the state 0. Now, we can either insert 5 or 10. If we insert 5, then its state transitions from 0 to 5. If we insert 10, then its state would transition from 0 to 10. Similarly, we can do for any state of the vending machine, and its state would transition to +5 or +10 of the original state value.

image.png

const vendingMachine = Machine({
    initial: 0,
    states: {
        0: {
            on: {
                INSERT_5: "5",
                INSERT_10: "10",
            },
        },
        5: {
            on: {
                INSERT_5: "10",
                INSERT_10: "15",
            },
        },
        10: {
            on: {
                INSERT_5: "15",
                INSERT_10: "20",
            },
        },
        15: {
           on: {
                INSERT_5: "20",
                INSERT_10: "25",
            },
        },
        20: {
            on: {
                INSERT_5: "25",
            },
        },
        25: {}
    }
})

You can visualize and interact with the state machine at xstate.js.org/viz. (Copy and Paste the above snippet)

๐Ÿ“š Continue Learning

I have introduced you to the basic concepts of FSM. You can do a lot more using xstate!

References


Support Me!

BuyMeACoffee