XState for State Management in React Apps with David Khourshid

Joel Hooks
InstructorJoel Hooks
Share this video with your friends

Social Share Links

Send Tweet
Published 4 years ago
Updated 2 years ago

Joel and David chat about the big ideas and the essential questions of State Management and State Machines. Additionally, David also gives a walkthrough of XState, XState Visualizer, and the upcoming dev tools for XState.

Key Terms

XState - is a library for creating, interpreting, and executing finite state machines and statecharts, as well as managing invocations of those machines as actors.

State Machines - a mathematical model of computation. It is an abstract machine that can be in exactly one of a finite number of states at any given time.

Combinatorial Explosion - is the rapid growth of the complexity of a problem.

Resources

Visuals Explanation

Source: https://www.stately.dev

These notes include: highlights, expansion of key terms, code blocks, and links to additional resources. They follow the same structure as the recording.

What are the big ideas of State Management?

  • It all comes down to applying big ideas from the past, for example, State Machines.
  • One of the biggest problems related to State Machines is performance.
  • The problems with States are not new.

Why is this hard to understand these problems?

  • There's a mathematical explication to this. Once you have more than one piece of State in different places, you faced Combinatorial Explosion.

  • Combinatorial Explosion

    A combinatorial explosion is the rapid growth of the complexity of a problem due to how the combinatorics of the problem is affected by the input, constraints, and bounds of the problem.

    Combinatorics is an area of mathematics primarily concerned with counting, both as a means and an end in obtaining results.

  • An example of this is having ten main ingredients and having the output be 100 different dishes.

  • The most neglected variable is time when it comes to managing State. We can only think about this in abstract ways.

  • "We (developer) do most of the State management in our heads."

    • There's no concrete way to communicate our understanding of States. This is one of the reasons why we have State Machines.

What are the Essential Questions when people work with State Management?

  • First, identify all the pieces of State that you're dealing with.
    • How is this information organized?
    • How can this data change over time?
    • How can you model this data?

What's a Finite State Machines?

  • "XState is like Redux with Rules"
  • A finite state machine is a mathematical model of computation that describes the behavior of a system that can be in only one state at any given time.
  • Finite State, you can only be in one State at a time.
    • It's more of a mode, "I'm awake & I'm asleep."
  • It also describes how one can move from one State to another.

What's the difference between a State Machine and Statecharts?

How are State Machine addressing the big ideas of State management?

The Overlap of music and State Machines and Statecharts

  • When you look at music, there are infinite ways to express a melody; inherently, there are rules.
  • Music makes you a better visual thinker.
    • This is an example when it comes to modeling State solutions.
  • Music is centuries old; its theory is old. Computer science is the music theory of programming.
    • Music theory answers why "this" works, much like when you start using a library, and you realized that it's an elegant solution to a specific problem.

Building a Statecharts for JavaScript

  • The inspiration came from David's first job working with repetitive workflows. Wanting to solve this problem led to researching State Machines.
  • Early days it was called "Estado," the Spanish word for State.

Demo of XState

Code sandbox demo

  • Normal React Development:
    <div className="App">
      <h1>{toggled ? "Toggled" : "Nope"}</h1>
      <h2>
        {state.value} ({state.context.count})
      </h2>
      <button
        onClick={() => {
          send("TOGGLE");
        }}
      >
        Toggle
      </button>
    </div>
...
  • The problem is the all the business logic is inside the event handle.
  • If you have more business requirements, you'll need to add 'defense logic' to handle more use cases.

Adding XState

import { createMachine, assign } from "xstate";
import { useMachine } from "@xstate/react";

const toggleMachine = createMachine({
  initial: "untoggled",
  context: {
    count: 0
  },
  states: {
    untoggled: {
      on: { TOGGLE: "toggled" }
    },
    toggled: {
      entry: assign({
        count: context => context.count + 1
      }),
      on: {
        TOGGLE: "untoggled"
      },
      after: {
        1000: "untoggled"
      }
    }
  }
});
  • useMachine(machine, options?) - a React hook that interprets the given machine and starts a service that runs for the component's lifetime.
const [state, send] = useMachine(toggleMachine, { devTools: true });
console.log(state);
const [toggled, setToggled] = useState(false);
  • We are creating an event-driven approach to handling toggles.
  • All the logic is handle inside toggleMachine
  • With State Machines everything is an event (time is an event).
  • Existing machines can be configured by passing the machine options as the 2nd argument of useMachine(machine, options).
context: {
    count: 0
  },
  • We can add a side-effects count: context => context.count + 1 without affecting our main State.

XState Visualizer

What's the workflow for design States?

  • Pen and paper work pretty well. Modeling the behavior of a user is complicated.

  • Dev Tools for XState (coming soon)
    • CodeSandbox also works pretty well for prototyping state.

When is XState not appropriate?

  • You don't need a library to implement State Machines. You can use patterns in each language.
  • XState becomes more valuable when representing Statecharts.
  • XState version 5 will be smaller. It will be explicit, small, and fast.
  • See Twitter

Joel Hooks: [0:00] I've always been like, "I'm stuck at CSS. I'm no good at CSS. I don't do CSS. I hate CSS. I should probably learn CSS. I know a little Flexbox. I want to hire somebody to do CSS for me," which is what I did pretty quick at the Egghead. I just couldn't learn it.

[0:15] I was watching y'all XState video, and I was like, "Oh damn. I should learn CSS" because CSS has, one, completely transformed since I was first introduced to it and watching y'all at work and collaborate and just tinker with it. That was a little simple example, but it was like, "OK."

[0:35] Now I'm committed to stopping the CSS excuses. It's directly related to watching that video and thinking, "This is actually really cool." It even uses Sass, but I want to take Sass out of the mix. I just want to learn this tool, which we all do. It's really cool, like just a neat space. It's not a tutorial. You're showing stuff and teaching people but not in...Following along is challenging.

David Khourshid: [1:06] We want to eventually do sort of form tutorials just because not everyone has a two-hour attention span to watch us struggle for two hours when they want to learn something.

Joel: [1:16] But some people do. They like the depth of context you get from that versus an Egghead course. If you've ever watched an Egghead course, it's like this. It's a nutshell format where we pack it into a diamond. Now it's up to you to spend four hours to unpack 30 minutes.

[1:34] Like the opposite, right? It isn't like you can go in and watch tiles XState course in an hour and be done. Now you have a lot of work if you really want to understand it. It goes both ways to me at the end of the day.

[1:52] Another project of mine, I've been polling everybody that subscribes to Egghead. I send them an automated email. I ask them, "What are you struggling with? What's your area of research? What's hard?"

[2:04] State management has been like a perennial favorite for...I've been in frontend development for 20 years through Authorware and Macromedia, doing all sorts of stuff, not necessarily frontend Web development but the idea of building UIs and interact with them.

[2:26] It's been a problem, particularly in frontend. State is a problem of life. UIs in particular, it feels like people tend to struggle with that. That's where the conversations came up. I started researching who's thinking in the space, who's particularly relevant in terms of React.

[2:50] React is the big gorilla in the room, and then chaining out from there. It's not a framework problem. To me, not your framework, right?

David: [3:03] No. It's not in the language problem.

Joel: [3:06] No. We're talking about state machine, obviously. I, in 2009, wrote unittest for a finite state machine and ActionScript 3. I look at XState, and I'm like, "Guess what, it's like the same exact thing." It's like the principles and the tools. Syntax and structure is a little bit different, but it's not even that much different. It's better now.

[3:35] XState is the gem. I'm looking forward to getting into that. I want to start out with a few general questions because, like you said, it's a thread that goes across. What would you say are the big ideas in state management as far as, let's say, frontend or UI programming?

David: [3:58] The big ideas as in my big ideas or just big ideas in general?

Joel: [4:02] Either. What are the big ideas that are the common problems, the big ideas that you see carrying over from language to language and solution to solution?

David: [4:15] What I've been doing is just applying big ideas from years past. For example, state machines and state charts, all of those are really old ideas. A lot of the bigger ideas that people are starting to think about don't just relate directly to how you manage state even though, like you said, that's an everlasting problem.

[4:34] One of the bigger problems too is performance-related, like deeply updating state, how to split state or should you even split state, and maybe just have it in one big global store like Redux would do which, of course, causes performance problems which are mitigated by selectors, etc., etc.

[4:53] None of the problems with state are new. All these are problems that have existed for many, many decades.

Joel: [5:08] Why do you think it's so difficult for people to get their heads around? Why do people keep responding? Is it the glutton of choice? What makes it such an issue for people, do you think?

David: [5:21] There's a mathematical answer to this. It's combinatorial explosion. If you have one piece of state, like someone's name, that's extremely easy to manage. It's a string, you update the string. Something else might listen for changes on that string, etc.

[5:41] Once you have more than one piece of state, and once you have more than one place where that state can be managed, then you get into this combinatorial explosion problem.

[5:52] Just a short summary of what a combinatorial explosion is. It's like, have you ever been to a restaurant, a Mexican or a Chinese restaurant, and basically, all the ingredients that they use for every single one of their dishes, it's like five ingredients? Where you have chicken, lettuce, guac, and whatever. All of their dishes are just a combination of one or more of any of these items.

[6:15] As a result, you get five-page menus with hundreds of items.

Joel: [6:20] You end up at the Cheesecake Factory.

David: [6:22] Exactly.

Joel: [6:22] Where they drop a novel down on you, and it's like, "Here you go. Choose what you want."

David: [6:26] Exactly. Then they come back two minutes later like, "Did you decide?" It's like, "No, I didn't even get halfway through." The same problems are with states too. You don't know how state is going to change, when it's going to change, what the possible and impossible states should be. All of that is hard to manage.

[6:44] That's why I say pretty often in my presentations that the most neglected variable is time. I say that because we don't treat time as a first-class citizen when thinking about state. How our state changes over time is something that's important to think about, not just what the general shape of our state is.

Joel: [7:05] That's why you have exponential, but then you add time into it. You're pulling it this way and this way, and you end up with space. We literally, as humans, can't hold it in our brains. At some point, it gets so big that you can't think about it anymore. You can only think about it in a certain scope or a certain size of state that you can hold in your mind at one time.

[7:30] Then you leave the computer, you go eat dinner, you try to enjoy life outside of it, come back to it the next day, and...Not back to square one, but you're having to reload that all into your brain [inaudible] at that point.

David: [7:43] That's an important thing too. Where do we do our state management? For most developers, we do it here. We do it in our head. That means when we want to communicate how the state is supposed to change over time to any of our teammates, we have to tell them verbally.

[7:57] We don't have a concrete way of showing them, you're here, and then when this happens, now you're here. This could happen only when these conditions are true. You either have to dig through the code and try to get an understanding of what the original developer was thinking, or you have to verbally talk to your developers.

[8:15] Either way, everything is in your mind, rather than in the code.

Joel: [8:23] That's why we have a state machine. This is one, maybe, of many solutions. What are the questions we should ask when we're trying to solve this? I call them the essential questions. What should they be asking when they sit down, and it's like, "This is out of control. I can no longer even think about this. How do I choose a solution?"

David: [8:52] There's a lot of questions that need to be answered. First of all is what pieces of state do you have? That's the most important thing. Let's say you're creating a form. You have user information, maybe billing information, if you're doing some sort of checkout flow.

[9:07] You want to know how all that information is organized. Is it local? Is it external? Are you hitting an API to get extra information? It's how that information or data is related to each other, and also, how that data could change over time, like I said.

[9:24] That needs to be clearly modeled. You need to be able to choose some solution, technique, or pattern that allows you to clearly model that. For example, what good is a form library without any validation? These are things that you have to think about when thinking about all the different ways that your app can use the states, interact with the state, and change the state.

Joel: [9:48] What is a finite state machine? How does it come into that equation?

David: [9:57] A finite state machine. Of course, XState is a state machine library. I like to call XState Redux with rules.

Joel: [10:01] I like that.

David: [10:02] A finite state machine. Basically, it has a state, but it has what's called a finite state. The finite state means you could only be in one state at a time. This is where I differentiate between state and data. Data is anything like someone's name, age, the price of an item, or something like that.

Joel: [10:24] Boundless.

David: [10:24] Yeah. Finite state is more of a mode that you could describe something in. For example, I am awake right now. I could also be asleep. I can't be awake and asleep at the same time. That's impossible. That's what the finite state represents.

[10:44] Also, a finite state machine describes how these finite states can go from one state to the other state. For example, if I'm awake, and I go to sleep, that's an event that happens, then I'm asleep. Only when that happens can I transition from the awake state to the asleep state.

[11:07] I can't do anything ridiculous. If I'm awake and I start eating cereal, then I'm asleep.

Joel: [11:11] That's not an event that triggers sleep.

David: [11:14] Exactly. Hopefully not.

Joel: [11:16] It might for some folks. Hopefully, you gain the medical attention that you need. This is new to me. We mentioned XState. We're going to look at that in a bit. What's the difference between a state machine and a statechart? How do those relate? What is a statechart? How does it relate to a finite state machine?

David: [11:39] As much as I talk about state machines, state machines have limitations. State machines can represent one state at a time, which is fine for simple use cases, but when you're trying to describe many things that could be represented as happening at the same time, then it gets into your combinatorial explosion again, like we talked about. Now it's formalized combinatorial explosion.

[12:04] Finite state machines can't represent absolutely everything. Also, the more states you have, the more transitions between those states are possible. It becomes hard to manage. Thankfully, this problem was solved in 1989 by a professor by the name of Professor David Harel, who invented statecharts.

[12:26] You could think of statecharts as hierarchical state machines or extended hierarchical state machines. You could have states that are nested within states. You could have states that are orthogonal to each other, which means technically, it seems like you could be in two states at the same time, but that's a different way of representing a single state.

[12:48] Basically, it's a way to organize your states. State machines and statecharts are equivalent. Statecharts are a much simpler way of representing complex state machines.

Joel: [12:58] To go back to the sleeping example. If I'm sleeping, I can also be dreaming or in the REM state, or sub states and that sort of thing would be part of the process, where you are still sleeping. This is also you're in other states as well.

David: [13:18] Actually, that's a really good example. Let's say that you're awake, you're sleeping. When you're sleeping, you could either be dreaming or having a dreamless sleep like you're in "Westworld" or something.

Joel: [13:29] State, and state, and state. Inception at that point.

David: [13:32] Exactly. If we didn't have nested states, then that would have to be three states. We'd have to have awake, dreamless sleep, and sleep with dreams. That's three separate states. Then we'd have to draw two transitions from either dreamless sleep and dreaming sleep in order to go back to awake.

[13:55] We're thinking, "Wait, it doesn't matter whether we're dreaming or not. If we wake up, then we're awake." We could group both of those sleeping states, both the dreaming and the not-dreaming state, into one parent state, which is sleeping. I like that example.

Joel: [14:16] Going back to some of the ideas of managing state in general, how are state machines addressing some of the problems and the big ideas in state management? Is it a way for us to wrap it so we can understand and communicate about it with other humans?

David: [14:33] Communication is very important. State machines have this concept of visualization. It's called states transition diagram, where basically, you have boxes and arrows, where each box is a state that you're in. An arrow describes how you could get from one state to the other state.

[14:53] Let's take a more practical example. Let's take a form that you submit the form. The form is loading. Then finally, the form is submitted. Those might be three different events. You could have a resolve events, where once resolve happens, you know that the form submission is successful.

[15:16] The way that this works is once the user clicks submit, it goes into the submitting state, and then eventually, we get an event, like a success, or resolve, or whatever, and we're in the submitted state. This is typically how developers program, especially if you're used to Redux, MobX, or something like that, is we do what's called an event action approach.

[15:44] What that means is we say, when we get the resolve events, it means we're done submitting. That doesn't always make sense, because you have to know that you started submitting in the first place.

[15:58] What happens if you're typing your form, and then all of a sudden, you have a resolve event come in? Then you're submitted, but that doesn't make any sense. A state machine is that Redux with rules I was talking about earlier, where we described that states have a very specific way in which they could go to each other or transition.

Joel: [16:21] To me, it's communication. It's communication between human to human, but then it's also how we think and communicate with the machines that we're trying to program too. There has to be some sort of bridge between entropy and what a machine can handle. The computers don't really care. It'll be in whatever state that whatever the data leaves it to.

[16:44] We're gaining control and an ability to reason about and think about the process is the big part of it. Have you read David Harel's book?

David: [16:57] He has a bunch of papers.

Joel: [16:59] He has a thick out-of-print book too. "Statecharts." It's a thick boy.

David: [17:05] I think it's called "Statesmates" or something like that. I've probably skimmed the book, honestly.

Joel: [17:13] I wonder if it's still relevant, is what I was curious. It was written in the '80s. That seems like forever ago in computer terms.

David: [17:22] You'd be surprised how often these old papers and old books are relevant in today's world. Even Harel's original paper on statecharts is very relevant today, even though the statechart formalism has evolved from that time.

[17:39] It's been adopted into UML. It's been formalized into the SCXML spec. One of my favorite books was written in 1999 or 1997, one of those years. It's about 20 years old. It's called "Constructing the User Interface with Statecharts" by Ian Horrocks.

[18:00] When I first read this book many years ago, I think it was like three or four years ago, I was like, "This is an old book." You even had visual BASIC examples, really old Windows 98 examples.

[18:13] All of these problems are still relevant in development today, the way it describes the problems that developers commonly deal with with state. I'm like, "Wow, in 20 years, we have not moved much. We have not advanced much." The ideas in this book directly reflect David Harel's original thinking when he came up with the statecharts formalism.

Joel: [18:35] As species perhaps, we've very novelty-seeking and feel like we need to invent solutions. Do you think we tend to reach for invention over researching and investigating where people had been in the past?

David: [18:54] Yeah.

Joel: [18:55] What's the balance there that you look for?

David: [18:58] We commonly do. It's funny. A lot of people are asking how do I convince my team, or my manager, or my coworkers to start adopting state machines and statecharts as if it's something new, like they're trying to introduce a new library or something.

[19:16] I say two things. First of all, the ideas are extremely old and already well adopted in many different industries, not even just Web developments but they go to databases, and data electronics, aeronautics, car, automotive technology, all sorts of things.

[19:35] The second thing too is about that novelty factor. It is nothing new. I'm not trying to present a new thing. It's something that has been battle-tested over at least three decades.

Joel: [19:50] There's a ton of value in that. You mentioned UML. That surprised me. I never thought of UML as a state machine. Now that you mentioned it, it makes a lot of sense. They added a lot to it but...

David: [20:03] Yeah, they did. Statecharts are sort of UML, the good parts. The UML adopted statecharts and added a bunch of craps to it, but it's not necessary.

Joel: [20:16] UML maybe minus the Java stank.

David: [20:20] Yeah. Exactly.

Joel: [20:21] It was just enterprise application development and all that. That's what it is though. We're trying to build big apps. We've had hundreds of developers working on that. How do you even communicate? That's where tools like UML...

[20:35] I'm not even backing on UML because it can be done really well. It's like anything. You can take a good idea and expand it into badness. It's just people trying to understand and make a sense of it. There's like a minor miracle in anything ever getting done. How do we get work done and communicate is such a tough problem.

[20:57] I was curious. You're a piano player. DavidKPiano is your moniker. I was wondering. I've heard you talk about the overlap and how musical notation...There's some correlation with music, and state machines, and statecharts. I was wondering how that has come into play in your life and experience.

David: [21:25] I love that question because it does influence my thinking on state management application structure and organization. That's because when you look at music, it's so free, and emotional, and expressive. There's an infinite number of ways that you could express a melody or different harmonies.

[21:49] Inherently, there are rules. Those rules could be either understood like jazz music, or they could be written down like sheet music. Sheet music is a pretty declarative way of expressing something as emotionally expressive as music.

[22:10] That influences my thinking a lot. As a musician, it makes you a very visual thinker too. You are envisioning where your hands are placed, just the relation of the sheet music to playing the actual instruments, things like that. Plus, it's creative as well.

[22:31] A lot of people would ask me in the...We have a spectrum.chat/statecharts forum where people would present all different types of state modeling questions. The thing with state modeling is that there's no one right answer. You have to get creative.

[22:49] If you think about, "Oh, how do I debounce this form?" Well, think in advance. Then people would be like, "OK. Here's one solution." Someone will say, "Well, here's another solution." Both of them are done using statecharts, but they both differ in different ways. That's part of the creativity, is modeling the solution.

Joel: [23:12] I agree with you. We talk about composition. There's this terminology that is overlapped with music. There's almost a subjective aesthetic beauty too when people talk about code that they like. It reads. There's rhythm. I don't know. It's a metaphor that carries over a lot to me.

[23:32] One of the things that is interesting in music terminology and music notation is centuries old. It's a way to communicate and express feeling, emotion, and thought that has carried on since we began. We've formalized it and come up with a system.

[23:51] I feel like we're in the baby phase of doing that with computer code, because it is what it is. We're still trying to figure out. We had centuries to figure out with music. If anybody's ever tried to dive in the music theory, it's a subject of great depth.

David: [24:10] I've had to, yeah.

Joel: [24:11] I like to dabble with this too. I like to understand it because I'm a lover of music. What's actually going on here? It's like, "OK, there's a lot going on." I feel like a lot of the times, software is the same way. You can...

David: [24:24] Yeah. In fact, I'm glad you brought up music theory. Music theory, in essence, it answers the question, "Why is this particular melody so beautiful? Why does this feel a certain way? How do the harmonies interact with each other to make this sound nice?"

[24:42] When you see something like an elegant algorithm or an elegant library, that's a solution to a problem, instead of just using library and being like, "It works well, so I'm just going to keep using it," I'd like to think...I know many developers are like this.

[24:55] We'd like to think, "Why does this work well? What are the inherent patterns in here that make it a really elegant solution?" That goes to computer science. Computer science is the music theory of programming.

Joel: [25:10] I don't know. It felt like a modern music producer listening to jazz records to find samples that they can pull out and understand like, "Why is it structured? How will this sound good if I reframe it and I compose it a new way for people?" It's like grabbing a library or whatever, a snippet of code and using that in a new way. You can spend a lot of time thinking in that space. It's pretty wonderful.

[25:37] Out of all this, you're sitting around one day, and you're like, "I need to build a statechart library for JavaScript." What snaps? Where was the tipping point where you said, "F it, I'm just going to build it live"?

David: [25:57] Honestly, it stems from probably when I got my first job as a junior developer. We were developing all of these very complex, multistep forms. You could think of complex wizards where data may come in asynchronously. This was back in jQuery era where jQuery was the framework.

[26:17] If you go crazy, you might have backbone or something like that. jQuery was the de facto library that was used in pretty much every single application. When doing this, I'm like, "This is extremely repetitive. We're hard coding all of these things. When you click this button, go to here, and do this, and do that."

[26:40] We have so many forms to create. I wanted a simpler way to describe these workflows. That's when I started researching. I found out about state machines. Then eventually, that led me to statecharts.

[26:53] That's why the more I kept thinking about how I would structure my applications and my logic to fit that state machine model, the more repetitive it felt and the more advanced use cases I need. That's when I got to statecharts. I was researching libraries and eventually decided to make my own.

[27:16] Back then, it was really early days. I called it Estado because that's Spanish for state, and you have ES like ECMAScript. Anyway, I also found the SCXML spec which describes all of the possible things that could happen in a statechart in a nice, formalized, documented way. I adopted that. Then I created XState just to solve that complex state management problem.

Joel: [27:45] The other day, you blew my mind. You tweeted a fully functional XState visualizer-compatible state machine library in a tweet.

David: [27:59] Yeah.

Joel: [28:00] That's a segue. I want to see if you're into showing us a quick demo. I would love to see that. I don't know how you like to do the elevator pitch demo of XState, but maybe get into some code and a little tour. I would love to see that particular thing, if that's something we can recreate.

David: [28:27] Sure. Let me just...

Joel: [28:30] You said you had it. You said there's a spec. What was the spec that you just mentioned?

David: [28:35] It's called SCXML. All right. I didn't whip up anything. This is me being lazy. This is a create React app starter. Get Hello-CodeSandbox. Start editing to see some magic happen. Let's just model a very simple toggle. This h1 is going to say...I'm honestly making this up as I go.

Joel: [29:03] No problem.

David: [29:05] This is going to say, "Toggled." Then I'm going to have a button over here that say Toggled. Basically, the idea is when you click this, it's going to toggle or untoggle that thing. Wow, that button is really small. Let's upsize.

Joel: [29:21] Either on or off, right? We have two states.

David: [29:25] Yeah. Exactly. On or off, very beautiful UI over here. The idea is that in normal React, you would probably do something like const [toggled, setToggled] = useState(). We're going to say false. Then over here for toggled, you would have if it's toggled, you would show "Toggled." Otherwise, you would show...Nope.

Joel: [29:58] On your normal stream, you would have shown on the background effect in your styles and beautifying as you manage state. We've effectively managed state at this point.

David: [30:08] Yeah, sort of.

Joel: [30:10] Almost there.

David: [30:11] Yeah. Of course, we have to change the state so that's what this onClick is going to do. I completely forgot the syntax. Just kidding. When someone's watching you, all of a sudden, you can't type anymore.

Joel: [30:28] You should see me doing it, it's so brutal.

David: [30:30] We're going to set toggled to...It's not toggled right now. When we click it, we want to set toggled to true, so when we click toggled, it's toggled, but obviously it doesn't go back. Normal React developer would say, "Well. if it's toggled, then do false, true." You could also do like...

Joel: [30:54] Toggled?

David: [30:55] Yeah, ! Toggled. Still, there's a problem with this. Where does your business logic live? It lives right here, right inside your event handler. It doesn't live in any centralized place because you have your event handler here. What if you want something else to toggle it like another button or something?

[31:14] Then, you would have to just copy this over here. My paste isn't working. Copy this over here, take two. I cannot copy anything right now. Copy, paste, nope. Anyway, just imagine...

Joel: [31:29] Just imagine if copy-paste didn't work. What would we do as developers?

David: [31:34] State machine here is broken, weird. Whatever, we're just going to ignore that. Anyway, we have toggled nope, toggled nope, toggle nope. Let's see that we have more business requirements. Let's say that we only want to toggle it five times.

[31:51] Once it's more than five, you can't toggle it anymore. Then, you would have to add another variable here. You would have to keep track of the number of toggles. Then, you would have to add some defensive logic over here like toggled and counts > 5. If it's that, then don't even try toggling.

Joel: [32:12] I feel like I've written that code before.

David: [32:15] Let me just give a quick...This is a very contrived example, by the way. Let's say that we wanted to add XState into here. This is weird. I can't even type. Oh, wait, yes, I can. The thing is just not showing.

[32:31] OK, there we go. Let's say we add XState into there. We're also going to add XState React, which provides a useMachine hook that allows you to use XState with hooks. We're going to import { createMachine } from 'xstate'.

[32:51] If you saw the tutorials that Kyle Shevlin put out on XState on Egghead, he uses machine. It's exactly the same thing. In version 5, it's just going to be moving createMachine, because a lot of people confuse machine as a class constructor, something like that. We're also going to use machine. We're going to create a machine and we're going to use it too. That's going to be from XState React.

[33:14] The idea is that we want to define how these states can move between each other. We have two states. Let's make that toggle machine first, createMachine. We're going to start in the untoggled state. We have two different states. We have untoggled and we have toggled.

[33:45] The way that this works is like useReducer. If you've ever used reducer, then using this is going to be pretty straightforward.

Joel: [33:53] Is it literally useReducer or is it just like useReducer? It feels literally like I'm doing the same thing, but there's a machine behind it.

David: [34:05] In fact, you could think of a machine as a glorified reducer that also handles side effects for you. It's the only two things that it does. It changes state and it does side effects. If you really, really want to make your own statechart thing with hooks, then you could just create your own fancy useReducer and just toggling with useEffect.

Joel: [34:24] I think of it like a switch statement. We have a state and we're going to make a decision based on what that current state is, and here's the answer, which is like Reduxy style. You'd think of a switch statement, but a reducer doesn't really care. It's just making a reduction and giving you an answer. In this case, it's running through a state machine to do that and provide you with that answer.

David: [34:49] Exactly. You could pretend that this is just like useReducer. We have a state and with reducers, you have dispatch. I like send because send is just shorter. This state is going to contain a whole bunch of stuff, console.log(state). This is also beautifully described in Kyle's Egghead series too.

[35:11] It includes a ton of stuff, but what we want is the value. That value is going to represent the finite state value. In fact, I'm going to do it over here. I'm going to print the states.value, just to show you.

[35:30] Whenever we click this button, instead of setToggled -- this is the idea of an events-driven approach -- we're going to send an event instead. We're going to send toggle. You're going to see this is not going to work because it stays on untoggled, which is our initial state, so that's working.

[35:50] What we also want to do is we want to transition between these states. We want to say, just like in plain English, onToggle, we go to toggled, and when we're in the toggled state -- let's type onToggle -- we go to untoggled. Now, when we send the...

[36:13] [crosstalk]

Joel: [36:13] It's the same event both. It doesn't even...We're hitting a switch.

David: [36:18] Yeah, now, we're moving the changing of states, all that logic to this machine rather than putting that logic inside our event handlers. This is already going to eliminate so many bugs and you could see that we have onToggle, toggled, untoggled, toggled, etc.

[36:38] With state machines, everything is in events. Just to get a little bit more creative, have you seen those silly machines where you press the button, it opens up and then some mechanical arm presses the button again to close it?

Joel: [36:51] Yeah, it's a little troll machine, basically.

David: [36:54] Yeah, the troll machine. Let's make a little troll machine. We have onToggle(toggled), but we want to say after, let's say one second, we're going to say 1,000 milliseconds, we go back to the untoggled state.

[37:08] XState allows you to do this because time is just an event. What this is doing inside of the machine is it's saying, "I'm queuing up in events to fire after one second and go right that machine," so you could just think of this as any other events. Let's see what happens...

Joel: [37:25] Like a shortcut syntax that XState gives us to basically do a setTimeout for us under the machine.

David: [37:32] Yeah, so instead of doing XState. after 1000 blah-blah-blah, that's what that is. It's just a shorthand for basically a custom event. When we click it, it goes toggled. After a second, it goes back to untoggled.

Joel: [37:46] Well, there's all sorts of logic you consider in there. This is like a simple timer, but at that point, it's the full expressive power of JavaScript in terms of what you might want to do based on those events and transitions.

David: [37:59] Right. If we want some extra data, for example, if we want to know how many times we've toggled it -- I'm just going to do a simple count example -- then, instead of having to keep an extra variable over here, we could just put it in what's called the machine context. That's the contextual state or the extended state of the machine.

[38:21] We still have our finite states, toggled and untoggled, but now we also have a counts that we're keeping track of. This is where side effects come into play because I want to say, every time that we enter the toggled state, I want to increment that counts.

[38:38] Here's how you would do it. You would have entry, because it's an entry action, and we would assign...See the import, OK, good. Assign returns an action object, and that action object tells XState, "This is a side effect I want you to execute."

[39:01] It doesn't execute the side effect, it just represents what the side effect is. In this case, counts context, we're going to say context.counts + 1. Every time we enter this toggled state, this is the side effect that's going to happen.

[39:17] Let's add that counts right over here. I'm going to add parentheses. I'm going to say state.context.counts. Now, whenever we toggle it, it's going to increase that counts. We still have that troll logic where we click, and it untoggles itself.

Joel: [39:40] But that isn't adding to our count, because it's not us doing it really. That's just how you set it up. That's the logic of it, is when we move into the toggled state, not the untoggled state. It's not every transition, it's every move into a particular state.

David: [39:56] Yeah. That's the basic, how to get all of this working together. One more thing, the reason that it's in this object like syntax, some people like it, some people don't but...

Joel: [40:14] I can ask, when does the visualizer come into...When do you jump into this? This is the XState visualizer, and you can keep showing it, but I'm wondering, at what point in your workflow are you opening up the visualizer to start working that way? I assume you do, otherwise it wouldn't exist. It's not just a teaching tool. It's a practical tool.

David: [40:35] Right. You can either do it before or after, like in the course of, as you're working on your C machine and you're designing your states, this becomes useful at a conceptual level. I forgot, for whatever reason my copy-paste is not working, so we're going to do this with the mouse.

Joel: [40:54] You might be able to right-click. It's a pain.

David: [40:57] Copy. Let's see if this works. Paste. There we go. What I did was I just copied my machine definition verbatim. We have to use machine not createMachine, because this is running on an older version of XState, but it still should work. I think it's just my command key not working.

[41:16] Anyway, when we update this...Oh, OK. Yeah, it's visible here. You could see that we're in the untoggled state. When we click Toggle, you could see it just going from toggled to untoggled. You could see our logic, the exact same logic that we're representing visually here in our React app is also in the visualizer, just in a more abstract way.

Joel: [41:44] Obviously, we're like in a little toy contrived example, and authenticity is often super complex. I was curious as to, what's the workflow?

[41:57] Personally, when you're jumping back and forth and when you're designing and you're thinking about the state of your application, do you use a pen and paper or write it out in JSON and then moving back and forth? What goes into the thinking about state and describing it?

David: [42:21] I definitely use pen and paper. I don't know if you could see this, an example of some state machines I draw when thinking through a problem. Sometimes, the problems, the logic that I have to model, it's pretty simple, so you don't have to have to think you're thinking about...

Joel: [42:39] You're thinking about it. It's a section, right?

David: [42:41] Yeah.

Joel: [42:42] You're not necessarily thinking about this, but you take a little slice of the state and when you're thinking about it, like in a small, small way that we can get our head around.

David: [42:51] Yeah. It makes things a lot easier with regard to thinking of like, "All right, but what if the user does this? What if I want to make a request?" By the way, this is something that's often forgotten about. What if the user makes a request, and the user wants to cancel it?

[43:07] In a lot of React apps, there's no way to do that because it's not explicitly programmed. Promises don't have a needed cancellation.

Joel: [43:13] Yeah, the promises.

David: [43:14] But the cancellation is just an event. Your machine should reflect that when you cancel, it should have different behavior. It should cancel that promise, ignore the results of that promise, whatever you want to do.

[43:28] There's a lot of things that do make me pull out my pencil and paper and think through the problem. One of those was debouncing. You could represent debouncing or throttling as a state machine just because it has that innate notion of delayed transitions and things like that.

[43:49] Other things too such as, what if you have multiple events coming in, and you want to orchestrate what happens if this finishes before that or that finishes before this?

Joel: [44:02] When you're on pencil and paper, you're at the whiteboard with a collaborator, is this, the visualizer, also how you would represent it, with pencil and paper or on a whiteboard?

David: [44:16] Yeah. The visualizer is the easiest way for me just because I could write my scrap JavaScript code in here. I'll put a machine, and then I could just copy and paste this directly into the visualizer itself. I am working on DevTools as well though.

[44:32] Basically, the idea is if you have a state machine here and you use machine, and then you set DevTools to true, then it should show up in the DevTools. I don't have them right here, but I could show you. I'm experimenting with...This should be fun.

[44:53] I made a timer example. This can sort of beat the UI of what those DevTools are going to look like, at least in part. I made this timer. I forked this CodeSandbox in. When you interact with....

Joel: [45:05] If I was an emoji right now, it would be the heart-eyes one. This is amazing.

David: [45:06] When you interact with this timer example that I made, it goes through the different states like pause. It goes to the pause state, and then it goes back here. The difference between this and the visualizer is, obviously, you can't click the events to cause it to change. You do that within your app itself.

[45:31] Let's reset it, it goes back there. I'm working on a workflow for that because I want it to be a more seamless process of, you're working on your state machine within your app and you also want to visualize at the same time, especially as you interact with the app. It's just a work in progress.

Joel: [45:50] This is an aside, do you use CodeSandbox a lot for prototyping?

David: [45:56] Yeah, if it requires more than one JavaScript file or TypeScript, I'll use CodeSandbox. Otherwise, if I'm playing around within the animation or something quick, I'll use CodePen, just because it has everything set up there for me and it's a little bit quicker than CodeSandbox.

[46:16] This basically sends all of your codes to the cloud, compiles it and then sends it back to you in a representative way on every save, which CodePen is a little bit quicker...

Joel: [46:28] It's VS Code in the cloud. It's a me thing. I use it all the time. I'm just fired up. It's kind of my go-to, in general, like if I just want to experiment or play, and then you can share and move to GitHub and really enjoy...

David: [46:44] I love CodeSandbox. It's a great tool.

Joel: [46:46] XState, when is it not appropriate? I don't need XState. What I've seen, and this is where I probably get it because I think, personally, if I was given advice, I would say, to me, it's as useful as Lodash. It would be something that I would bring in, just bring it in. I don't know what the ramifications are in terms of over...I don't really care.

[47:13] I'm not like a wonk about the size of my payload, to the extent that if this is useful and I can deliver a better product. That aside, is this just something that you just bring in automatically? Is the state machine appropriate for, essentially, all applications? Set timer, you probably don't need that.

David: [47:36] As far as using XState in all applications, I'll be the first to say not necessarily. You don't need a library at all in order to implement these state machines. In fact, state machines are just a general pattern. You could search for state machines in literally any language, Python, C#, whatever, and there's patterns for doing that.

[47:57] Most commonly, the pattern is using a switch statement or some other type of pattern matching statements and, boom, you have a state machine, like you have a finite set of enums, a finite set of events that you could have, and there's your state machine.

[48:12] Where XState becomes more useful is in representing statecharts. The algorithms for doing these nested states, like I have over here, and also things like delays and parallel states and other cool statechart features such as history, entry, exit, transition, actions, transient transitions, etc., those are all pretty complex.

[48:37] There's an extensive list of algorithms on the SCXML specification for how to do that. That's something that you definitely don't want to reimplement yourself just because it is hairy. It's also why XState is not the smallest library. It's not Lodash huge, but it's about the size of MobX.

[48:58] There's also XState/FSM where if you do just one of flat state machine and you want it to also be visualized and work the same way as XState, then it's just a kilobyte. It's a very small library.

Joel: [49:15] I've seen a few people that use, and Ryan Florence in particular says he highly recommends XState, but he isn't to the point where he needs all of that. He just uses his own custom hook useFiniteState.

David: [49:30] Which works. That Tweet you were talking about, you can make your own state machine with just a few lines of code. Ryan does use XState in a few projects, and he also just uses XState-influenced or state-machine-influenced patterns in the rest of his code when he can't exactly bring XState in.

[49:52] If you look at the Reach UI component library, all of that is based on state machines and statecharts, and they did a really good job with it. They don't use XState though.

Joel: [50:02] It would be a big dependency probably for that purpose. Just as a plug for Reach UI, if you want to go see some React component development, that source code is absolutely...I peruse it like reading a nice book. It is a wonderful, happy place for code. They've done a great job of using the state machine style.

David: [50:31] I will also say that XState version 5 is going to be a lot smaller. We're doing a lot of simplification. Part of this means that some of the magic will be removed, but it's replaced by one line of code that you have to add.

[50:46] It's funny. The really useful libraries that people use, like RxJS and stuff, they have this size bloats just because people keep asking for all of these features. It's like, "Wouldn't it be nice to do this and that?" It's this designed by community thing that contributes to...It's really large size.

[51:10] XState is taking a different philosophy. It's saying, "Be explicit if your feature request is not part of the SCXML spec. Then do it in user land. We're not going to just throw it into the library, and we're going to try to keep it small and fast."

Joel: [51:25] That's interesting to me because it's like you get to work off of a spec. That's such a cool thing. Maybe a lot of open source maintainers don't have that privilege, I guess, of being able to be like, "Well, here's the spec, and we're just going to go by that." Sorry, but you're going to have to...You're on your own on that one.

David: [51:44] Yeah.

Joel: [51:45] That's great. As an open-source library, how is that going for you in terms of managing that and maintaining a library? What's that experience been like?

David: [51:58] I do get some help from a fervent open-source contributor by the name of Mateusz Burzyński. He also does work on Redux-Saga and a few other libraries. He's been extremely helpful. He's one of the other main contributors too, and I am glad that I have other people contributing to the project, finding things in the documentation that could be improved or even added.

[52:22] Someone recently added how to integrate XState with Svelte. That's a PR that's in progress. Also, XState Vue, there are customs hooks for XState Vue, the composition API that were contributed completely by external contributors, which I am really happy about.

Joel: [52:43] That's cool.

David: [52:45] In fact, it makes working with Vue pretty awesome because the exact same code that I write for my React projects, I could just copy that machine code, put it in Vue and the logic works exactly the same.

Joel: [52:59] Is there a machine library anywhere like a catalog? Probably not, but...

David: [53:02] No, not yet.

Joel: [53:07] It's just interesting like I don't even know how you'd do that, but it just occurs to me because you're modeling a slice of reality in a way.

David: [53:17] Yeah.

Joel: [53:18] This is how a thing of this nature functions, like how reusable and transportable might that be from context to context.

David: [53:26] It's something that's been asked for before and it's something that I definitely want to do once I have a little bit more free time.

Joel: [53:32] It'd be odd. It's an odd thought. How would you even organize that and what's the taxonomy and the support of something like that?

David: [53:41] Yeah, just imagine a website where you could be like, "I want this machine because it represents the logic for a combo box" or something that I really want.

Joel: [53:49] Or like the Reach work, what they've done inside of Reach. They've focused on accessibility, and here's the machine that represents this type, like a dropdown box or whatever, a really complex component. That's kind of interesting. That's a good thread to explore.

[54:07] David, I really appreciate it. Thanks for showing the code, and it's great to chat with you about this stuff.

David: [54:14] Thank you for having me.

Joel: [54:15] All right, man. It was great hangin' out. Nice to see you. Bye.

David: [54:19] You, too.

Joel: [54:20] Bye.

egghead
egghead
~ just now

Member comments are a way for members to communicate, interact, and ask questions about a lesson.

The instructor or someone from the community might respond to your question Here are a few basic guidelines to commenting on egghead.io

Be on-Topic

Comments are for discussing a lesson. If you're having a general issue with the website functionality, please contact us at support@egghead.io.

Avoid meta-discussion

  • This was great!
  • This was horrible!
  • I didn't like this because it didn't match my skill level.
  • +1 It will likely be deleted as spam.

Code Problems?

Should be accompanied by code! Codesandbox or Stackblitz provide a way to share code and discuss it in context

Details and Context

Vague question? Vague answer. Any details and context you can provide will lure more interesting answers!

Markdown supported.
Become a member to join the discussionEnroll Today