# Reactive State Machines and Statecharts

Canonical: https://davidk.dev/talks/reactive-state-machines-and-statecharts-reactiveconf-2018/
Video: https://www.youtube.com/watch?v=DrHccvns-L0
Speaker: David Khourshid (@DavidKPiano), creator of XState
Type: Conference talk · Event: ReactiveConf 2018 (Prague) · Year: 2018 · Duration: 28:50 · Views: 2688 (as of 2026-10-19)
Topics: Statecharts, State machines, Reactive programming, Visual modeling, XState, Event-driven architecture

## Summary
29th - 31st October 2018, Prague, Czech Republic ------------------------------------------------------------------- Reactive State Machines and Statecharts

## Key takeaways (quoted from the transcript)
- My application is a huge state machine, you shouldn't, you should be using multiple state machines that all communicate with each other. (19:00)
- The more lines of code we write with finite state machines, we see an initial decrease in complexity. (22:00)
- The way that hierarchical state machines work is if the transition is invalid here, it checks the parents, and if it's invalid in the parents, it goes to the parent and so on. (25:00)
- What you really want is in enumeration, you want your state to either be loading or error or success, and never all three at the same time. (28:00)

## Chapters
- 0:00 Introduction
- 5:00 We have idle searching, success in failure…
- 13:00 Using this, I want to see which of those paths results…
- 19:00 Since stay charts are visual learning…
- 24:00 The way that hierarchical state machines work is if the transition…
- 27:00 You could feed that data into a decision tree or a…

## Transcript
[0:00] All right, well, we are all here for one reason, and that reason is because reactive systems are difficult to develop. I mean, that's the reason we're all here. And it doesn't matter whether you're working in the front end or the back end, when we're dealing with reactive systems, that's systems that work. When events come over time, then we have so many problems to think about and so much complexity. That's a possibility.

[0:00] So my name is David Khourshid, also known as at @DavidKPiano, and I do this weekly show called the key Framers, and I do it with my friends Shaw. And what we do is we tackle these complex user interfaces and we try to recreate them using HTML, CSS, and only a little bit of JavaScript. And so as we do all these, we start to discover patterns where your application or your user interfaces could be in different states at different times.

[1:00] And you have to handle and predict how you should handle, for example, animations or user application behavior, based on what happens over time. So, just to describe what, what the problem is. In an example, let's say that you have a button, this fetch data button right here, and it does just as you would expect, you press the button and eventually you get a results. So now let's see what happens when that operation takes a little bit of time so we could show a spinner.

[1:00] Sure, that helps, right? That tells the user, Hey, your dad is coming eventually, and then we get the data, but that's not always how users behave. For instance, if I saw this screen and it was taking maybe 10, 15 seconds, you better believe I would be pressing that button repeatedly until and making all of these API requests. But you, as a developer, your smarts, your liking. I know what I'm gonna do.

[2:00] I'm going to disable that button and that way the users never going to, you know, be able to click it more than once. But what if your user is me and I go into the Dev tools and I make it enabled again? Now I could just keep making API requests. So, in my opinion, the most neglected variable in software programming is time. Sure, we could think of our applications on the front-end, back-end.

[2:00] User interfaces. As you get a state, and when an event occurs, you get a next state. We've seen this equation many times, but this doesn't tell the full story. In fact, we have to think about what happens over time, where when an event occurs, we get a next state. But then we have effects that happen too, and these effects could in turn send more events. And so we have so many different ways of dealing with time, whether it's callbacks, promises, async, await or my favorite, which was just talked about, observe a balls.

[3:00] So we, we have many different solutions to this problem, but we don't have a very precise way of describing it. And so we end up with code like this, for example, let's let's put our actual fetch button to code, so we have a search request here. We have in the events handler and we're fetching the data and then we show the data when the results are retrieved. But of course, we need to add a loading indicator and so we go ahead and do that.

[3:00] So we have a loading flag, but we also have to turn that loading flag false. When we get the data. Just so that we're not showing a spinner. But what if there's an error? So now we have an error flag and that boolean flag. We have to set it to true and set the loading black to false because we don't want to show it loading and then the error at the same time.

[4:00] Okay, so now what? If we try to restart the search, then we have to reset those flags, set loading to true, error to false. It's the right, looking a little complex. So now we have to get even further. Let's say we want to cancel the search request. I don't know if you could see that, let me zoom in for you. This gets extremely complicated and so this is called the bottom-up approach.

[4:00] And that's when we stuff a lot of logic into our event listeners. In this logic could be all sorts of logic, conditional logic, business logic, party logic. I don't know. Side effects. You could update state, maybe have another side effect. You could have a sync operations inside your event handler, you know, make some updates to either local or global state.

[5:00] And eventually, you know you, you want to test, but it's so complex that you don't even know where to start. So this is called bottom-up code, and bottom-up code has a few attributes. First of all, it's very difficult to test because things inside your event handlers happen over time, it's difficult to understand. - if you tried to describe a feature, you have to look at so many different events handlers to see where this feature is defined.

[5:00] It will contain bugs just because you can't test every single possible use case, it's difficult to enhance, so when someone comes to you and says, we need to add a feature, it becomes very difficult. - because you need to understand the logic in all of your event handlers. And features, in fact, make it worse because they increase the complexity of your application behavior. So I play piano, you know, that's why my name is David KPI.

[6:00] My last name is not piano, but I play piano, so that's why. And so in Vienna, we have this thing called music notation. But the interesting about this is that this is understandable by anyone who plays any instruments and has had musical training, it doesn't matter which instrument. I mean, you probably can't play this on, I don't know guitar or something. This is mostly a piano thing, but at least you could read it, you could understand it.

[6:00] And so as a musician, I constantly think, can we have something like this for software where we could model the behavior in a declarative way and reuse it? No matter what framework we're using, what libraries were using, or even what languages were using. And so that brings me the finite state machines and statecharts. Some of you might have taken this class in university or looked up a Wikipedia article. It looks really nasty, so just try not to go that route.

[6:00] I'm gonna try to explain it to you real quick. So a finite state machine has one initial state, that's your starting state where your app starts at. It has a finite number of states that your app could be in. And then we have to define what the user or what other events can happen, that transition between those states, and then we have some final states which tell the overall state machine. Were done processing.

[7:00] So let's take a look back at our Fetchit components. So we have an idle state. And then when we do a search event, we go to this searching state, and now we could define the search events. To not do anything to stay in that searching state instead of repeating the action of searching. And then, depending on whether we resolve or rejects that promise, we go to a success or failure state. This is understandable by anyone, no matter if they know programming or they don't know programming.

[7:00] All you have to do is follow the arrows and events, and you could. It's just like a follow your own adventure type of thing. So what does this look like in code? The way I write it, you could write it using switch statements, but I prefer to use object notation. And there's a few good reasons why. First of all, we could enumerate all of these states, and it's a little bit more concise than switch notation to.

[8:00] And so we're defining here transitions between states, so here's all of our states. We have idle searching, success in failure, and then whenever an event occurs, we map it to what the next state should be, it's that simple and so our transition function, but this is all it has to be. It's a simple object to lookup, you get the state whenever you receive event, look up what the next state should be based on that event.

[8:00] And, in fact, you could put it inside of a React. I know we're all talking about React hooks, so I decide to make my own. And so here's a simple traffic light example in React. And so here's what it looks like in real life. I'm doing story the same thing here using my library XState, which is the same notation that you saw, but it's a library that handles a few more things.

[9:00] So, for example, this is a Flickr application. And so if I type Prague, do the search event and I cancel, I have cancellation built in, because when I go to cancel, it goes to the gallery, states and so on. Search success. There's no advance transition defined for that event, so we get natural cancellation. And then, you see, we could model things pretty clearly. That looks pretty good by just. At lunch. So, yeah, and so, with this software, books are made visually clear.

[9:00] If you were to make a simple application like this, where you have idle loading success, all of your code works, all of your unit tests fast, good for you, your codes broken still, and here's why. What's wrong with this code? Take a look at the loading state. What happens if we have an error? This is something that linters and type systems and so on. For the most part, scans, check, and so we should define a state to handle the error.

[10:00] But then there's another problem, this failure state, it has no way to go back. So we could visually see clearly that we're missing a transition from failure back to loading so that we could retry that request. And this is made visually clear by visualizing the state machine. So does this scale? No, it doesn't. But that's why there's statecharts, also known as extended or hierarchical state machines. And it's a visual formalism for complex systems made for reactive systems.

[10:00] And this was invented by David Harel in 1997. To give you an idea, that's over 20 30 I cants math right now, but it's like many, many decades ago. So none of this is a new idea. These are very old ideas that have been used in many industries in having proven time and time again to work. So statecharts add a little bit more. First of all, we add actions we have on inch reactions on exit actions and actions within transitions, and actions are those side effects that I was talking about.

[11:00] Those are the things that actually make your application do things like display to the screen, send a fetch request, etc. Guards are what prevents transitions from happening if certain conditions aren't met. And then we have ways to simplify state machines, and this is where statecharts scale. You could nest dates together, you could do parallel states, which we'll explain in a bit, but that means that you could have two, two states that are both active at the same time.

[11:00] And you have other cool little things like history and things like that, so here's where parallel states come in handy. There's a thing called Carta, I think Cartesian, the Cartesian product, where let's say that you're modeling a text editor. And you have bold, italic and underlined buttons to model the state of your text editor. You have to take in accounts the On/off states of each of those buttons. Which, if you remember your permutations combinations.

[12:00] That's through the power of three or eight states, add another one, such as strikethrough, that becomes 16, 32, 64. It exponentially grows with statecharts. We could simplify that by just making those orthogonal regions or regions that don't really affect one another. And so nesting helps simplify your same machines in the same way. For instance, over here, we see that the success and failure state have the same outgoing transitions on the search events.

[12:00] They both go to surgery so we could group those two states and simplify the behavior of both of them.

[13:00] And so here's an example. I love doing reactive animations, and so this is one that I saw, and it was complex enough that I modeled it as a state. Charts write down, yeah, right down here, and I'll show you this day turnin in it. But when I first saw the animation, it was not working. It was complex enough that I had to think about all of the possible different states that could be, for example, this rectangle.

[13:00] Dragging. What happens if I let go? Without selecting in elements? You have to keep that in mind, but now I'm in the state where I have elements selected, so now dragging is going to do something different. It's going to allow me to get rid of these days and make my weekends a little bit longer. And so the cool thing about this is this model. As a state machine, I could copy and paste this configuration and visualize it.

[14:00] And so this is not a manual step, it's an automatic step. Where the visualization of the state machine is over here for you, you see every single state automatically generated on this visualizer. And so if we go back to the gallery example, you could see that's exactly what I did here. And not only could you visualize it, you could simulate what happens when certain events occur. And so this becomes a very powerful tool for showing stakeholders or project managers, and so on.

[14:00] So, as I mentioned, I was working on this library, called XState, for a while now. And. I just write it over here. I'm blind because the lights are right in my eyes. But I want to know how many of you are actually using XState in your job? Okay, I'm gonna assume a few hands are up anyway, so XState. It handles finite state machines, but it also handles many aspects of statecharts, like hierarchical states, parallel states.

[15:00] Actions, which are declarative side effects that you could model and mock if you want. History, states, conditional transitions and a few more things. And so I want to show you a quick preview of what's coming up. So the next state, I've been working on a few things. And one of the things is called the assigned property, and this is a or the assigned method. And so this is a declarative way of updating your data.

[15:00] So you define your state machine here. Now we've all programmed something like a tic-tac-toe application. Those are not difficult to do, so I decided to model it as a state machine, where we're in one of three states. We're either playing X 0, X 0. We have a winner or we draw, and whenever we're playing, we check if there's a winner or if there's a draw, and as long as the move is valid, we update the board using those assign actions.

[16:00] So in this way, it's sort of like Redux, so you get an event and then you handle what happens with that event. And so the result is this. You have a live game where you know you could see who wins, who loses, you know you could do a draw if I could. Oh, oh, one, well, anyway. So you might be thinking, this is cool, I guess you're just you're just programming this in a different way.

[16:00] I already know how to do this with Redux, I already know how to do this with my backs. Heck, I don't even need a library to do this. So why would I want to model, like, go through the trouble of modeling it as a state machine or statechart? I'm wondering if that's actually one of the questions, I can't see it right now, but model A, that's a statechart. And actually, you know, do something with it.

[17:00] So what I did? And of course, this is a React application using. That exact same state machine. What I did was there's this get shortest value pass function that's available in X8. And that does some graph theory algorithms, where basically traces all of the shortest paths throughout the state machine. And using this, I want to see which of those paths results in a draw, and so these paths, which are pairings of states and events, and states and events.

[17:00] So just like, a do this and do that, then do this and do that. I'm looping through them and I'm using Puppeteer to actually, you know, click the right elements and map, like, for example, this play event, it's just clicking the correct square. And so if all goes well, come on. It will stimulate every single possible game state in which a draw occurs by actually playing through the game. I didn't tell my tests how to play tic-tac-toe, I just gave it the exact same state machine that I used for my application.

[18:00] And you could see, it's generating all of those possible play states. And so I could go further, I could ask it, like, show me all of the games where X wins and five moves are less, for example. And so all of this is now available in XState version four, which I literally just released a half hour ago. And so it includes a few extra things, such as external state, delayed transitions and events.

[18:00] An interpreter? So you don't have to roll your own final states, which are very, very useful for modeling simultaneous processes and making sure that they all finished.

[19:00] Sort of like promised at all. Invoking external machines, which have been a big question, like, why would I model? My application is a huge state machine, you shouldn't, you should be using multiple state machines that all communicate with each other. And new visualization and simulation tools which are coming up. And there's so much more, and I probably don't have time to talk about all of that. But one big thing that I want to emphasize is that XState and these tools that I'm working on are nothing invented.

[19:00] In fact, as I said, stay charts were invented in 1997, and they've been used in many different technological fields, such as automotive technology, embedded electronics, avionics and more. And there's even a W3C standard for it, that's. Been out since September 2015. And this standard is used by tool such as QT. And you can do state machine tools which work for different languages such as Python, C++, Java, and more. And so what that means is that the same code that you write for XState in theory, can work in different environments.

[20:00] Whether you're using C++ or Java, or Python, or anything that can interpret this standard. And so there's many advantages of using statecharts, but my favorite is this story from NASA, where they actually used a charts to auto code the Curiosity Rover. Now think about as an engineer trying to unit test this, integration test this. You want to make sure that you have absolutely everything modeled, because if one thing goes wrong, if one test fails, that's a multi-billion dollar mistake.

[20:00] You know, you don't, you don't want that on your resume. So we have visualized modeling very precise diagrams that they could hand off to designers and project managers. Automatic code generation, which means they take their diagrams that they manually manipulate and they generate code from them. Comprehensive test covers that test, all possible things that could happen and accommodation of late-breaking requirement changes. This is one of the most important ones because we've, I'm sure all of us are in agreement, that we've never been in the project where changes didn't come later.

[21:00] And so that's where complexity starts to creep in. And we have all of these to-do comments in our code, like, get rid of this, this is a hack. That's because of these late-breaking requirement changes that stay charts, because it's visually modeled, solved for you. Now, of course, I need to talk about the disadvantages, too. First of all, there is a learning curve. But since stay charts are visual learning, visual language in a visual formalism, I find that this learning curve is mitigated.

[21:00] By just intuitively understanding what these diagrams mean. Modeling does require planning ahead. That doesn't. That means you can't just go into the code and start coding away. You actually have to sit down with a pencil and paper and actually plan out what you're going to code. But the good thing about that is that once you have all of that on paper, it becomes really easy to transfer the code. And, of course, you can't smuggle, absolutely.

[22:00] Everything, it's not a hammer that just works for everything. You have to pick and choose what parts of your application can be modeled as a statechart. And, of course, there's complexity trade-offs to by what we do. Using bottom-up programming, we see a linear increasing complexity. The more lines of code we write with finite state machines, we see an initial decrease in complexity. But, as we talked about with state explosion and all of that, that exponentially increases.

[22:00] With statecharts, there's a higher upfront cost. But the more complex your application becomes, the IT levels out and it becomes easier to manage. And so there's a few outside sources that I've seen using statecharts and using my library, which I'm really excited about. First of all, Brian Florence's workshop taught me, which is live tech training for industry experts. He was one of the first to use XState when I first announced it a little bit over a year ago for the payment flow.

[23:00] And so I literally dug into the minified code looked for be a statechart definition and copy pasted into the visualizer. And, you know, I saw how everything worked, so that was pretty cool. And if you're using Gatsby, Gatsby uses X8 for some of its internal processes. And so I'm very excited to see that. And the newest one I've seen was by a Hatchet Corp. who made vagrants their vault product. They have this advanced user flow where they have interactive tutorials for the user as they're going through their application.

[23:00] And so there's a quick video of how that looks. And so it was really cool to see XState being used for this, and that is open source as well, so there's many resources and tools on the internet for using state machines and statecharts.

[24:00] And the community is growing everyday, and I hope that, you know, it grows even more. Because I'm very passionate about it and I want more software developers like you all to become passionate about it. Because it saves you time and energy and effort, and it makes things a lot easier for everyone involved. So, basically, I want you to make your code do more. Thank you, reactive pause. Thank you David for the nice talk.

[24:00] In the meantime, there has been a slider battle going on. So some people were like, Relax, Sokka, relax, I go, go, go, and the other group was like, additional state states. Which one do you prefer? Oh so, with steam machines, since it's just a transition, functions just to reduce our function. You could use it with Redux Agha, you could use it with Redux, with Mob, ex with View, and Euler React, so that doesn't really matter.

[25:00] How do you handle additional state data that only exists in certain states? Will you put them into your main state? So that goes into state machines communicating with external state machines? So, for example, let's say you're creating a to-do list, your to-do item could itself be its own state machine, with its own internal state that communicates with the parents. And these are the patterns, just as you would expect with React, where you listen to on change, accept, React.

[25:00] Doesn't have a very good story of the parents communicating with the child. Yet to use rests for that. But it's just an example of how that work. Let's see what happens by defaults for invalid, transitions, for invalid transitions, what happens is it defaults. Well, so the way that hierarchical state machines work is if the transition is invalid here, it checks the parents, and if it's invalid in the parents, it goes to the parent and so on.

[26:00] So it's the same type of event delegation that happens in your normal DOM manipulation and all of that. Otherwise, there is strict mode where it will throw an error saying you cannot do this. It's invalid. But as a developer, you should be handling invalid transitions yourself. Would you like to take the behavior trace? How do you consider them? Have you considered them? There are hierarchical state machines on steroids to use in game development.

[26:00] And out of 10, what do you think? So, I looked briefly into behavior trees and also decision trees, that they're the same thing, they're probably not. But I talked about how you could use date charts and state machines for analysis, and based on that analysis, you could create adaptive user interfaces. And so what that is, you analyze every time a user does an event.

[27:00] You give each transition, so from state to state, you get that transition of weight, so if more users are going from one. State to the other, then that edge gets a higher weight. And so you could feed that data into a decision tree or a behavior tree and automatically adapt the application to best fit the users. So it's sort of like you're getting rid of a be testing and instead you're having the application adapt itself to make users happier.

[27:00] I think we have two more minutes. If there is one you like, we can take it all right. If you see machine, how do you know if you need to show the spinner or not? Based on flags or the state name, so you should do it based on the state name, here's why flags are bad. Let's say you have is loading and is error, and is success. By having those three different variables, technically, all three of them could be true at the same time.

[28:00] And then you have, like, I remember my car got struck by lightning a few years ago. And all the lights came on. And some of the lights were like, everything's good, and some of the lights were your cars dead. And all those happened at the same time. And so that's what that looks like. And as a programmer, you are having to keep track of all, right? It is loading and showing I shouldn't be showing is error.

[28:00] But what you really want is in enumeration, you want your state to either be loading or error or success, and never all three at the same time. So you want to try to make impossible states impossible? Thank you, thank you, thank you. [Applause] you.
