DEV Community

loading...
Cover image for Future of state management in React with XState

Future of state management in React with XState

Jakub Skoneczny
Full Stack Web Developer (React, Node, PHP). In spare time, I enjoy playing the guitar and reading about space.
Updated on ・5 min read

It is common to see a poll on social media asking for the most common ways to manage state in React. In many cases, the options are limited to MobX or Redux, React Context + Hooks, Recoil, but more recently, also XState.

With the other tools being well known and primarily accepted (maybe without Recoil, since it's also new), XState is still relatively unknown to most developers.

Note: The purpose of this post is not to compare XState to other state management tools, but rather to tell about the problem it solves and give you a quick introduction, so you can jump and start learning by yourself.

So without further ado, let me tell you more about XState.

What is XState?

XState is a library that brings state machines to Javascript and Typescript world. State machines are a mathematical concept that has been introduced for describing complex systems. To explain it quickly, imagine a block schema - you have multiple blocks connected with lines and arrows. Those blocks represent states in your application, and lines with arrows represent the flow between those states.

Block Schema

If you start from the first block, you can only transition into the block you have a connection with. Therefore you are automatically prevented from transitioning to any block you want. And this is the most significant advantage of using state machines - you can only transition between states that have defined and allowed connections.

Let's now drop this analogy tho schema and use the proper terminology.

Every state machine has:

  • a finite number of states (such as idle or loading),
  • a finite number of events (such as { type: 'SEARCH' } can trigger a transition between states).
  • a list of defined transitions, which say, "Given some event, go from state idle to pending".

Also, every state machine may have:

  • a context which is data stored inside the machine,
  • a final state, after which the machine stops

Okay, so we know what a state machine is. But when seeing a designed schema, it is easy to think about it as a machine. Let's see how one can think of anything like a machine and write it using XState.

Describing ordinary things in the form of a state machine

Think about water. Just regular water. How does it behave? If we start with the liquid form, it freezes when it's cold, and it vaporizes when we boil it. We can even heat it more and more until it becomes plasma. Let's try to write it down in block schema:

water machine schema

When water becomes plasma, we can no longer heat it because it can't change farther. We can only freeze it from there. If we start to freeze plasma, it will become a gas again. The same thing is with ice. If water is in ice form, we can't longer freeze it. We can only heat it.

If you look closely, you will notice that water has no final form. We can always make a transition between its states. Let's see how we could implement it with XState.

import { Machine } from "xstate";

const waterMachine = Machine({
  initial: "liquid",
  states: {
    ice: {
      on: {
        HEAT: {
          target: "liquid",
        },
      },
    },
    liquid: {
      on: {
        HEAT: {
          target: "gas",
        },
        FREEZE: {
          target: "ice",
        },
      },
    },
    gas: {
      on: {
        HEAT: {
          target: "plasma",
        },
        FREEZE: {
          target: "liquid",
        },
      },
    },
    plasma: {
      on: {
        FREEZE: {
          target: "gas",
        },
      },
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

We need to import a Machine creator and pass it into the machine's object. Machine's object has states property where we define our states. In each state, we can put the on property, which handles events that are defined within.

Event handlers are objects in which we can put target property pointing on a different state. This means that when the HEAT event in the ice state comes, the machine will transition from an ice state to a liquid state.

This explanation may sound complicated, but it starts to be straightforward if you look into the code.

Using XState with React

XState is a Javascript library, which means it is framework agnostic. But when it comes to React, XState gives us hooks for using a defined state machine inside React components. All we need to do is to call it, and then we have access to properties like:

  • state that represents the current state of the machine and its data,
  • send, a function that sends events to the machine

With that, you can use your machine inside components. You can read its current state (e.g., rendering different components based on state), you can read its context (for displaying data), and you can send events to that machine (make transitions between states).

Just see the usage of our water machine inside the React application:

import { useMachine } from '@xstate/react';

// use hooks inside your component
const [state, send] = useMachine(waterMachine);

console.log(current.value)
// 'liquid' 

// send event for making a transition
send("HEAT")

console.log(current.value)
// 'gas' 
Enter fullscreen mode Exit fullscreen mode

Prototyping and debugging with ease

State machines built with XState can be visualized with the usage of XState Viz. This fantastic tool allows you to do many things with your machines like debugging, live preview, and interactivity. Just see how we can interact with our water state machine.

water machine visualized

Designing complex systems with state machines

When thinking of large web applications, often it comes for us developers to introduce huge and intricate features. Some components are built with dozen or hundreds of child components that also have some logic inside. Coming up with a sound state management system for that can be tricky. Fortunately, state machines fit well for that.

A state machine can be just like a single block in block schema. Your application can have multiple state machines, which communicate with each other. Also, you can have one main state machine which controls the others and enables that communication.

And all of that logic nested inside multiple state machines can be later visualized with XState Viz and be interactive. What a great business value for your PM!

In my opinion, this is the most valuable advantage of state machines over other state management tools - it's not just a library for state management. It is a whole new ecosystem for designing and controlling business logic.

Going further with XState

If you want to dive deeper into XState concepts, I highly recommend visiting the official XState documentation. Documentation is written clearly and is pleasant to read. For those of you who instead prefer video sources over reading documentation, I have prepared an introductory course that is available on Udemy - Introduction to State Machines with XState and React.

Thanks for sticking for that long! If you are interested in the latest tech news, you can follow my account since I plan to post here regularly. I also tweet on a regular basis so that you can follow My Twitter account as well!

This post has been originally posted on my personal blog. Please make sure you see it there as well :)

PS. Comment if you have used XState in production!

Discussion (0)