Skip to content
  • Services
    • Strategy
    • Customer Experience
    • Agile Delivery
    • Security
  • About
  • Partners
    • Aha!
    • Amazon Web Services (AWS)
    • Atlassian
    • Cloudflare
    • GitHub
    • InVision
    • Ionic
    • Pendo
    • Radar
    • Vue.js
  • Work
    • Modus Create Labs
  • Insights
    • Blog
  • Careers
  • Contact
  • Services
    • Strategy
    • Customer Experience
    • Agile Delivery
    • Security
  • About
  • Partners
    • Aha!
    • Amazon Web Services (AWS)
    • Atlassian
    • Cloudflare
    • GitHub
    • InVision
    • Ionic
    • Pendo
    • Radar
    • Vue.js
  • Work
    • Modus Create Labs
  • Insights
    • Blog
  • Careers
  • Contact
January 5, 2021

Getting Started with XState, React and Typescript

Front End Development, JavaScript, React

When starting a new React project, one of the most difficult steps is deciding how to manage the application state. Historically, many projects have used local state, or have used libraries like Redux, and others have implemented a custom mix between the two.

In this traditional way of managing state, as the application grows, we start adding more and more data to keep track of the application state, and this can lead to many bugs or invalid states, typescript can help immensely on this front as it enforces a state model to be respected, but still there is a lot of room for bugs to surface.

We’re going to use another pattern of managing state that aims to solve this problem, state machines, a mathematical model of computation, that describes the behavior of a system that can only be in one state at any given time.

State machines have been around for a while and, as you’ll see, using them is a more formal and deterministic way of managing state.

In this post, I’m going to show you why and how to use state machines to handle state in a React application with a lot more confidence.

What is XState?

XState is a library that allows you to create, interpret and execute state machines and statecharts. State machines are abstract models defined by a finite number of states, events and the transition between those states. Statecharts are basically State Machines on steroids, they introduce nested states, parallel states, and extended state, among other things.

When using State Machines, it’s necessary to model the entire set of States, Events and Transitions beforehand. This can seem like a tedious exercise, but it will give us total confidence in what is happening at each moment, because anything that wasn’t explicitly defined can’t happen.

Now that we’ve got the concepts down, let’s get coding.

Project Setup

First let’s create a simple React project, for that we can use create-react-app, and setting to use the typescript template.

npx create-react-app xstate-getting-started --template typescript

Then, the next step is to install XState. xstate is the core package, as we need this to create our state machines. @xstate/react provides an easy way to use hooks for integration with our React components.

npm install xstate @xstate/react

The project is good to go, let’s get started creating our first state machine!

Modeling the Machine

This tutorial will use as an example a Traffic Light model, so in order to define the model, we need to go through the very basic states, events and context that a traffic light has.

In its most basic form, a traffic light has 3 states, green, yellow and red.

What events does it have? A traffic light loops through the 3 light colors, and nothing else. So we’ll only need a single NEXT event, that will trigger a transition of the Traffic light to the next color in the loop.

We’re using Typescript on this project, since XState is written in typescript, it provides first-class support to strongly type State, Events and Context, so a wise move would be to type our domain. Events in XState are what causes the state machine to transition from its current state into its next state. Our Event type is declared as a Union Type of all the possible Events.

type TrafficLightEvent = { type: "NEXT" };

The last step is to define how our state looks using something called Typestates, that is a concept where we type the possible state values, and how that value goes along with context, this can be really powerful on more complex machines, on this simple example will be used just to represent the possible state values, since the context will not be used.

type TrafficLightState =
 | { value: "green"; context: undefined }
 | { value: "yellow"; context: undefined }
 | { value: "red"; context: undefined };

Now that everything is typed, it’s ready to create the machine.

export const trafficLightMachine = createMachine({
 id: "trafficLight",
 initial: "red",
 states: {
   green: {
     on: { NEXT: "yellow" },
   },
   yellow: {
     on: { NEXT: "red" },
   },
   red: {
     on: { NEXT: "green" },
   },
 },
});
 

Let’s go over a couple details that were not mentioned before: the id –the machine identifier — and the initial state value, which is what state the machine starts on.

The states property is defined with the possible states, and how they should handle the events that can happen. So there is a property for each of the possible states that handle that Event, and also what state the machine should transition to, when the event is triggered.

In this scenario, every state handles the NEXT event, but this does not have to be the case. For example, if the ‘on’ property is missing on the red state, the machine will be forever stuck in red, since there will be no event that can transition from it.

And that’s it, that is our completed, working state machine.

Visualizing our State Machine

Now the cool part, let’s visualize it. XState’ has its own Visualizer tool: https://xstate.js.org/viz/
Visualizing the State Machine
Our traffic light state machine
It enables developers to see the machine, the possible states, and how events transition from one state to the other. In the visualizer itself, you can also click on the events, and that will show the state transitions, it’s really cool.

Now, let’s take our newly made machine, and implement it on a React component.

Integrating with React

import React from "react";
import "./App.css";
import { useMachine } from "@xstate/react";
import { trafficLightMachine } from "./trafficLightMachine";
 
export const App = () => {
 // Typescript will infer what current and send are here
 // And will provide useful information about usage
 const [current, send] = useMachine(trafficLightMachine);
 
 return (
   <div>
     <div />
     <div>
       
       
       
       <button> send("NEXT")}>NEXT</button>
     </div>
   </div>
 );
};

The first action is to import the machine and useMachine hook from the @xstate/react package.

The matches function is what defines what state the machine is currently in, so if it is in the red state, current.matches(‘red’) will be true.The send function acts a lot like the Dispatch does for redux, it just sends the event you want to the machine, in this case NEXT.

Running it and hitting the button, the traffic light colors will change!

Wrapping Up

Okay! Now you know what state machines are, how they work, why they are useful, and how to implement one with React. Even though this example is extremely simple, it will give you insights into how State machines can model complex business logic, and the confidence that they can give you on your projects. You can review the sample code.

Posted in Front End Development, JavaScript, React
Share this

Santiago Kent

Santiago Kent is a Full Stack Developer at Modus Create, passionate about writing code and shipping features. He is dedicated to learning new things and improving processes in just about everything.
Follow

Related Posts

  • React Navigation and Redux in React Native Applications
    React Navigation and Redux in React Native Applications

    In React Native, the question of “how am I going to navigate from one screen…

  • React Context API Global State Management
    React Context API Global State Management

    Modus Create's Javascript Community of Experts shares tips for getting the most out of the…

Subscribe to the Modus Newsletter

Receive the latest blog articles and insights every month from the Modus team.

Join Our Global Team

Would you like to be a Modite? We are redefining distributed consultative services. We have open positions throughout the globe.

See Open Positions

Let's Chat

If forms aren’t your thing, you can always call us (+1-855-721-7223).

Modus-Logo-Primary-White.svg
  • Services
  • About
  • Partners
  • Work
  • Insights
  • Newsroom
  • Careers
  • Contact
Virginia (US)

12100 Sunset Hills Road
Suite 150
Reston, Virginia, 20190
Tel: +1-855-721-7223

California (US)
12130 Millennium Dr

Los Angeles, CA 90094

Missouri (US)
609 E High St

Jefferson City, MO 65101

Romania

Str. Mihai Veliciu, no. 17
Cluj-Napoca, Romania
Tel: +40-0786-887-444

Costa Rica

2nd Floor, Plaza Koros, Av 3
San José, Santa Ana, Costa Rica

© 2021 Modus. All Rights Reserved.

Privacy Policy | Accessibility Statement | Sitemap

This website uses cookies.
These cookies are used to collect information about how you interact with our website and allow us to remember you. We use this information in order to improve and customize your browsing experience, and for analytics and metrics about our visitors both on this website and other media. To find out more about the cookies we use, see our Privacy Policy.

Accept
Privacy & Cookies Policy

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.
Necessary
Always Enabled

Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.

Non-necessary

Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.

Scroll To Top