DEV Community

Cover image for Getting started with Finite State Machine using X-state.
ASAP_A1
ASAP_A1

Posted on

Getting started with Finite State Machine using X-state.

Introduction

State management in a developer's journey can be hell and bliss, and this depends on the library one chose and how well he grasps the logic behind it right? I must say using a state manager never got better when you can visualize your code logic and decide the kind of beans you're cooking.

In today's session, I'll show us how spectacularly the X-state machine works in practice, and how generously it can make your experience in development worthwhile.

What is a Finite State Machine

The finite state machine can be seen as a mathematical “model” that performs a certain computational activity that assumes an initial state and spins through different[specified] states and back to the normal [accepting state]...
More explanation can be found in my previous article "The finite state machine"

What is X-State

Unlike redux, recoil, Zustand, and a million others, X-State is a library that helps you create finite states, have a visual interpretation, and also execute the logic seamlessly where for instance you will not have to wrap your whole app in a provider, store something or dispatch anything. It's just easy to use and maintain. you can find more explanations here

Getting Started

In this guide we will start by learning how to make a simple dark/light mode, and furtherly a traffic light for our react application all from scratch.
You can find all the working code here on my Github.[drop me a star thanks!]

Setting up

We need to create our app to run this so let's run this;

yarn create react-app react-xstate-finite-machine
Enter fullscreen mode Exit fullscreen mode

or

npx create react-app react-xstate-finite-machine
Enter fullscreen mode Exit fullscreen mode

Moving forward, we add the xstate package to the app;

yarn add xstate @xstate/react
Enter fullscreen mode Exit fullscreen mode

Let's run our app yarn start or npm start[if you are using npm to setup], while our app is building.

Create a file with the name you wish and that is where we will initialize the state like so;

import { Machine } from "xstate";

export const switchThemes = Machine({
  id: "themes",
  initial: "light",
  states: {
    light: {
      on: { SWITCH: "dark" },
    },
    dark: {
      on: { SWITCH: "light" },
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

Break down

id: just like any state manager it is the name of the name assigned to the state.
initial: that's the [initial]assignment name to the state we want to work with.
states: this is the area we're the state recide.[light&dark]
switch & on: that is what we use to fire the action of switching the themes.

ShowTime

Now it's time to visualize the beans we have been cooking, and x-state provides us with a tool called the visualizer which will show us how our state will logically work.

state in action
Now you can see that the logic circle began from the initail state of light and when a switch is invoked it'll change back to dark. Nicely yhh?

Back to our code, we would like to see our state in action, so we call our state component to App.js, also in order for the state to function fully we have to call the useMachine hook from the x-state library and we should have something like this.

import "./App.css";
import { useMachine } from "@xstate/react";
import { switchThemes } from "./states/darkLightSwitch";

function App() {
  const [current, send] = useMachine(switchThemes);

  const handleSwitch = () => {
    send("SWITCH");
  };

  return (
    <div
      className={
        current.matches("light") ? "light-theme body" : "dark-theme body"
      }
    >
      <button onClick={handleSwitch}>
        {current.matches("light") ? "light" : "dark"}
      </button>
      <h1>{current.matches("light") ? "Light Turnels" : "Dark Moments"}</h1>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

NB the light-theme & dark-theme are my CSS classes and they are in their separate folder.

Exciting, isn't it? Now let's get even deeper.

Traffic Lights

Having learned how to add themes to your app why don't we go deeper yeah?
Our traffic lights will assume this looks for now;

inital app looks

We will add a traffic light system into the app and follow prior setup guides for the dark & light the theme, we will be having our trafficking[excuse my french] light state like so;

import { createMachine } from "xstate";

export const trafficMachine = createMachine({
  id: "trafficLights",
  initial: "stop",
  states: {
    stop: {
      on: {
        NEXT: {
          target: "ready",
        },
      },
    },
    ready: {
      on: {
        NEXT: {
          target: "go",
        },
      },
    },
    go: {
      on: {
        NEXT: {
          target: "stop",
        },
      },
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

Yet again visualizer to confirm our act;

trafic light preview

Moving forward we will call the state in our application and this time around we will be using our darling useEffect to set our timer for the traffic light action, and the entire code should look like this;

import "./App.css";
import { useEffect } from "react";
import { useMachine } from "@xstate/react";
import { switchThemes } from "./states/darkLightSwitch";
import { trafficMachine } from "./states/trafficControlState";

function App() {
  const [state, send] = useMachine(switchThemes);
  const [current, push] = useMachine(trafficMachine);

  const handleSwitch = () => {
    send("SWITCH");
  };

  useEffect(() => {
    let trigger = () => {
      push("NEXT");
    };
    let timer = setInterval(() => {
      trigger();
    }, [3000]);
    return () => clearInterval(timer);
  });

  return (
    <div
      className={
        state.matches("light") ? "light-theme body" : "dark-theme body"
      }
    >
      <div className="container">
        <button onClick={handleSwitch}>
          {state.matches("light") ? "light" : "dark"}
        </button>
        <h1>{state.matches("light") ? "Light Turnels" : "Dark Moments"}</h1>
      </div>
      <div>
        <ul className="light-container">
          <li className={current.matches("stop") && "red"}>
            {current.matches("stop") && "STOP"}
          </li>
          <li className={current.matches("ready") && "yellow"}>
            {current.matches("ready") && "READY"}
          </li>
          <li className={current.matches("go") && "green"}>
            {current.matches("go") && "GO"}
          </li>
        </ul>
      </div>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

You will notice the call of useMachinehook twice, now that's because x-state will not allow you to call more than two actions to the function like our normal useState wouldn't.

Check out the app in different modes.

active trafic on dark mode
active trafic on light mode

Voilà we have our genius mode activated yhh, do well to share with others. Merci beaucoup!

Top comments (0)