David Khourshid

What’s Next for XState?

Conference talk at ReactNext 2021. 28:19 long, 510 views on YouTube. Topics: xstate, visual modeling, event-driven architecture, statecharts, state machines, react hooks.

Watch on YouTube (ReactNext)

What is this talk about?

“The idea is that your app can only be in one of these states at a time, and each one of these states can handle events a little bit differently.”

“Believe it or not, even state machines aren't enough, and that's because our application logic gets so complex that instead of, you know, representing it by a few states.”

From the opening of the talk.

Key takeaways

  1. The idea is that your app can only be in one of these states at a time, and each one of these states can handle events a little bit differently. 3:00
  2. If you pass in a machine to useMachine, you get the current states and you get a send function which allows you to send events. 10:00
  3. The idea is that there is now a special event called XState.input, and any event starting with X8Thot is an XState specific event. 13:00
  4. You know, just as we explored new ideas that XState and state machines and statecharts enable. 25:00

Quoted from the transcript.

Full transcript

From YouTube auto-captions. Punctuation and capitals were restored automatically. Technical terms were normalized; some errors remain. 4,464 words.

0:00 Introduction

All right, thank you everyone. So yeah, today, I'm going to be talking to you about what is next and coming up in XState. So my name is David Khourshid, I'm at David key piano pretty much everywhere online. My last name isn't piano, I just like playing the piano. And right now I'm in California, so it's actually pretty early for me. I think it's like 12 55 in the morning. So bear with me, but yeah. So before we talk about, like, what's new in XState, I want to talk about the motivation behind why I even created XState in the first place. So the typical way that we, we create applications and have application logic is we tend to put application logic just where it is. You know, immediately used. So, for example, we do it in event handlers, or we just place them in callbacks or other just ad hoc locations throughout our app.

And we're all guilty of this. Like, if a user clicks a button and that button is supposed to do something, then we're going to try to put that logic right where that button click is. And that's really not an organized thing to do, just because, you know, we don't know, where all of our logic, lives. And so if someone were to ask you, like, what are the features of this app? or how is this app supposed to work? Now? You're finding yourself looking through dozens of different files, just trying to piece everything together, and there's no clear way of understanding all of your app logic. But with the rise of Flux and Redux and libraries like that, we have reducers. And so I really like reducers, because what they do is that they consolidate logic into a central location. So that all you have to do is send an events to a reducer.

So now we don't have things directly manipulating states, instead we have events that abstract that idea of something just happened and something else should handle it. However, the downside with this is that, all of the states in the reducer, like. All that data is combined. And there's no clear notion of like the app is behaving differently, like there's no, distinction between the different behaviors an app can have and by behaviors. I mean, just the different states. So, for example, your app can be loading, you could be on the dashboard screen, or you could be in a certain step in a multi-step form. And so each of those things have to behave differently. But right now you have to just add, defensive logic and say, if this, then handle this event this way, otherwise handle it that way. And so now we're really replacing, this ad hoc logic with the centralized logic.

But we're putting IF statements all over the place, which, you know, not really the best idea either. And so that's why, we have state machines, and what stations do. A little bit differently than reducers is that they separate, the behavior of your app into distinctive behaviors, or what is known as finite states. And so the idea is that your app can only be in one of these states at a time, and each one of these states can handle events a little bit differently. So, for instance, we might be in some idle states and when we start to load data now, we're in some loading states. And so when the event comes to load data and we're in the loading states, we could say, well, we don't handle that event. So, you know, we're just going to continue loading without doing any sort of double loading or anything else that would require. This defensive logic, um. But, believe it or not, even state machines aren't enough, and that's because our application logic gets so complex that instead of, you know, representing it by a few states.

Now we have even more states. And, we have to nest states and just organize things better once we have a combinatorial explosion of states and transitions. And so that's where statecharts come into play, so statecharts are a you could think of it as a superset of state machines. They include things like being able to nest states, being able to have parallel or orthogonal regions of states. Which still fits with the idea that there's only one state at a given time, but now your state is like a combination of two or more states. And there's a whole lot of other benefits to statecharts, too, such as, history. So being able to you know when you go back to appearance safe remembering the last child state you are in different actions like entry accident transition actions which is something that is often forgotten in handling logic we can't just depend on the state we also have to depend on the side effects that happen as a result of those states changes and so using statecharts gives you a more organized way of representing the different possible states that your application can be in and that's why you know when I learned about them you know many years ago I started seeing them everywhere and saw them as a really good solution not as a magical hammer that you know can you know hit every nail but just as something that's useful in like when your application gets more complex so state machines and stage arts were created by David Harel in he published the his seminal paper on it statecharts and visual formalism for complex systems in 1987. so this just goes to show you that this is really old technology and it's been adopted by UML and in other tools but we haven't really seen it used much in you know in the front end you know until like I started like pushing for it with the xs and stuff but the one of my favorite ideas with statecharts and state machines and things like that is that it's a visual formalism so you could think of a visual formalism as basically being a programming language that's fully visual and it's executable and so by visual I mean like they're a diagram there's something that you could draw on a whiteboard but that drawing that you create is precise which means that there is no ambiguity to it you could literally interpret it just like your computer interprets code so David Harel says visual formalisms are diagrammatic and intuitive yet mathematically rigorous languages and so I think that this is really key to being able to spread the knowledge of what our logic in our application is to non-technical people to designers even to other developers I mean think about the onboarding process for developers you have to really sit and explain like okay here's how our app works here's where these files are and what lives in which file?

And it just becomes really complicated to do that, and that's why the onboarding process takes a long time, even for technical people like developers. So, anyway, that's where I, you know, had the idea to create XState at first. I just want to play around with the idea of, you know, doing state machines and statecharts in the front end, but it definitely grew to something that's much bigger than that. So X8 allows you to represent state machines and statecharts in this sort of object formats, in JavaScript and TypeScript, and, you know, soon for other languages too. So take this date machine, for example. We have an idle state, which is our initial state, and when we search, we go to searching. And then a couple things can happen. Our promise can either resolve or reject, and from those, we could search again. So this is just an example of non-trivial application behavior. So this is represented in the state machine by using create machine. And, we have this object syntax where we specify the initial state.

And then each of our states. You can see, we have idle searching, success and failure, and so in our searching states, we have two transitions. So we have resolve, which will take us to the success state, and reject, which will take us to the failure state. And so this is how you represent it all, using XState. So, then, the machine will. When you get, like, for example the resolve event, it will go to the success state and then it will handle the events that you specify in there. And so the way you use this is that you could use it as sort of a peer reducer function. Just like this. Where you pass in the current states and you pass in the events, and this could be an event object too. And so the next state is going to have a value of searching might have some other data also contains the events in there. And you know, you could use this in Redux or any application, really?

But, uh. More commonly, you would do what's called interpreting a machine, and so this is actually making the machine alive and something. That holds its own state and is able to be subscribed to and notify of changes to states. And so, for example, here we are, sorry, we are interpreting the machine, and so whenever a transition happens, we log the state. And so now we could just imperatively send, in events, and, the console.log will just say, oh, okay. Now we're in the searching states. And it will also do things like execute side effects and things like that. So that's just an overview for, people who, you know, if you're new to Xtape, that's just a really brief overview of how it works. XD with React is, uh. If you're used to the useReducer hook, then this is going to be really similar. Instead of the useReducer hook, we are using the useMachine hook.

And you're going to get those same two familiar values from the tuple there. So if you pass in a machine to useMachine, you get the current states and you get a send function which allows you to send events. And so, for example, if we're trying to do a multi-step form, we might have a first date, a second state, a review state. And I'll show you an example of this a little bit later, and we can render the view based on which state we're in. And then when the form submits, we could send a submit event. And you know, potentially this might actually have some data in there, and so we could send it as an event to objects. But this is essentially the same as useReducer, except now you get the ability to spawn other machines to run effects. And you get a whole bunch of other helpers too, which is really useful when you're dealing with complex application logic.

So I also, wanted to point out some new features that are in XState. Reacts you know, because this is a React conference. And, we do have, you know, as of the last few months, a few new hooks. So if you've been using XState of the while, you might know these, and you might not. But, uh. One of the hooks is use interpret, and this is really useful because when you interpret a machine, you create an actor. And in. In the exit documentation, this is called a service, but essentially, this is just something that you could send events to, and you could pass this object around. So over here, I'm just passing it through a service context, and so we're providing that service as a value. Now. Keep in mind, this is never going to re-render, so use interpret is going to create that service only once. And so this is going to be really, really useful in situations where you want to share data globally between many components, but you don't want to do any sort of over re-rendering.

And so we use that context, that service context, and we get the service. And then we could just grab this dates and that send function from that service using the you service hook. And actually, this is deprecated for use. Actor. But, you know, both of them are going to do exactly the same thing. And yeah, now you have pretty much the same thing as a Redux approach, but you have more control over it. Because you could have many global state machines, or you could have a state machine that's shared between many components that scopes to those components, and maybe have a different one for other components, etc.

Play from 0:00

13:00 The idea is that there is now a special event called…

But speaking of re-renders, there's also the useSelector hook. And so if you have that service, like we talked about just now, you could use a oops. You could use a selector and select specific data from that states. And so this is going to, ensure that the component only re-renders when that data changes. And so, it's it's really good for performance and for, transforming data if you need to do it. So, yeah, re-renders are definitely top of mind when you think about using useSelector. So I also want to talk about a really cool upcoming feature that is currently in PR review. But it's something that we're all excited about, that's called XState, inputs, so, you know, this is part of X8 core itself. And the idea is that there is now a special event called XState.input, and any event starting with X8Thot is an XState specific event. But what this allows you to do is specify continuous inputs that is fed into the machine, sorting the flow.

Based programming sort of way, and so this allows integration with other libraries, especially in Reacts, to be a lot smoother. So in this example, you could see that whenever we have an input events, we're just going to log the states.input. And, you might be familiar with useQuery, so let's say that we have a query and, you know, we're fetching some data. What we could do is we could pass that result.data directly into input and useMachine. And that exit.input event is going to fire whenever these change. So now we don't have to worry about converting this to an event and useEffects or anything like that anymore. Just put it in input and it's going to feel just like, updated props in the machine. So this is going to make again third-party library integration a lot easier. One of the newest features in X8 core itself is what's called create model.

And so what cream model allows you to do is just. It's mainly for TypeScript benefits, but it has other benefits as well. It allows you to create this nice model object that provides things like in the sine function, which, you know, all this is strongly typed and you could pass directly into your machine. You could also create what are called events creators, so in this instance, I have update name. You pass in the value and then you just return the payload of that event. And so now, instead of instead of providing that entire event object, we could have a that event creator over there. So we could say service dot send update name David as opposed to service that sends type update name value David.

Play from 13:00

16:00 Version 5 gives us that opportunity to have stronger and easier…

You know, this just might be nicer for people who prefer that sort of style, but the main purpose of this is to have stronger typing for your events. All right, so another new feature, which, actually came out pretty recently, is States.Can, so State.Can allows you to see if I send this events to the state machine. Is it going to cause a transition? So is it going to cause, you know, the state, to change your actions, to fire or something like that? And so this is something that I actually wish that all state management libraries had, because, for example, in this. State machine. We see that in the inactive state we can toggle, but we cannot do something. So, you know, you could say in inactive state I can't toggle. That's going to be true, but do something is going to be false. And so where this is really useful is for things like forms, so, with forms.

Typically, you would say, disable this button if the form isn't valid, or the form is incomplete, or we're already sending it or something like that. And so you have all of these. If, you have a really complex, boolean logic expression, in there to, you know, to say whether that button is disabled or not. But now with exit, you could just say, like, states, dot can submit. And that's going to be either true or false, and so if it's invalid, it's going to be false, etc. But you reduce your logic to just will this event have any effect? And so that's why I really like these dates.can, and I really recommend you use it. This is available right now in XD core. Now I want to talk about version 5 for a minute, just because I am excited about a lot of the things coming up in version 5 and many people have been asking about it. One of the newest features is actually partial wild cards.

So that's going to let you specify, transitions for an entire group of events. So in this case, any event that starts with mouse or mouse dots, those events are going to be handled by mouse dot Star. So now you don't have to create multiple, transitions for those anymore. With, you know, copying and pasting, you could just do mouse dot Star and have those partial wild cards for events. So, there's also higher level guards, which has been something that's been asked for a lot. And so, now you could have things like and or and not from X8 guards and be able to, you know, create complex representations of guards. And I, I know you might be saying, like, Okay, why can't I just use, normal JavaScript for this? And you definitely can. But with this, you get some visualization benefits. Where you could, you know, visualize that boolean logic right inside the. Visualizer or the editor, or, you know, whatever other visualization tool that you decide to use in the future.

So, that's just a short list of some of the new features coming up. In general, what we're focusing on for version 5 is, first of all, everything is an actor. So we're not going to be treating services and observables and promises any differently. All of these are just going to be the same actor. Interface of something that you could send events to, and something where you could subscribe, you know, for events, uh. We also have in order assign, which this is a minor detail and something that you can fix in version four. But now all the actions are going to run in the expected order, so this is more of just a bug fix. Uh. Typing is going to be, you know, top of mind for us because we do want to improve the typing experience. So version 5 gives us that opportunity to have stronger and easier typing.

Play from 16:00

20:00 What this machine also enables is the ability to take that…

Also, it's going to be modular and smaller. The current X8 pretty much exports everything, which is why, you know, to some people it's sort of a big package. But with X8 version 5 you could choose which parts of XD you want to export. So as a result, it's going to be a smaller package size and there's many more improvements. Feel free to ask me after the talk, and I'd be glad to, you know, talk about just what we have planned. With you, but just, you know, just the code is not really like the. You know, the biggest thing that we have coming up in XState, it's more what X8 enables. So I'm going to show you an example over here. I have a checkout app where, you know, you could walk through it and select shipping method and go through here. This is my real email, that's not my real number. Go to payments, agree terms and conditions, place order.

So this is just an example checkout app, and this checkout app is controlled by this date machine over here. So you see, we have the card, state shipping, state contacts, payments and confirmation. Now this is all in React. But, this goes to show you that this machine. Has nothing to do with React. You can easily transfer to Vue or Spelt, or whatever other framework you want. But what this machine also enables is the ability to take that state machine and visualize it. And so you're gonna see, when we have XD inspect and we open it up with Stately..ai slash viz. It's going to visualize the machine right here for you. And this is our new visualizer that we released a few months ago, and so it shows you just a visualization of all the different states in our app. So when we, you know, for example, go through here and click through, you'll see that this actually updates, and it works in both directions too.

So if I click next over here, oh yeah, there we go. If I click next, it's going to go to contact in here as well. And so again, this is possible because we're describing our application logic in terms of this directed graph. But what's really cool is that this enables, turn this off from it. This enables us to do a lot more, too, where we could actually walk through that graph and auto-generate steps. And so right now, it's just finding the shortest path to the order confirmed state, and it's describing it in plain English, and that's because I add some descriptions to each of the states. But we could change the criteria and say, we want to, find where the scenario. Let's see if that matches confirmation. And we have a scenario. Dot, state, dot, context dot. What did I call it like? An address? Oh yeah, shipping address.

And so now when we say that, it's going to find the shortest path, but one that fits that requirement. And so now it's going to say, like, Okay, here's all the all the steps you need to reach that state. And so now you have, like, instant tutorials and documentation for users, and this becomes an excellent way to test your app. In fact, we could auto-generate just by passing that state in each of those events in, we could auto-generate the views, for each of those states. So we have a shipping address. And again, these are just simulating events in each of the app or each of the, steps that we do.

Play from 20:00

24:00 As far as state management libraries go…

So, yeah, this kind of thing becomes possible, and we're definitely going to build tooling around this kind of auto generation. So, yeah, I also want to show you that we are also working on a VS code plugin. And so this is going to allow you in the future to visualize your machines as you're working on them. So you could just click open inspector and see your machine visualized inside the VS code. So I definitely recommend you check out the VS code plugin. So, as far as state management libraries go, hopefully you can see that there is a difference between what exists for state management and what exists for state orchestration, where estate management just provides you a convenience. I guess you could call it like a storage container for states, and state orchestration is more about orchestrating. The, how different parts of your app talk to each other, the different behaviors of your app, and so that's what, you know, XData is really useful for.

So, yeah, we have a bunch of current modules, and we have, some future modules that we're working on, too. Or at least, you know, just thinking about things like XC form X8, router, X8. Query things that have been asked about a lot. So expect the in the XC ecosystem to grow a lot. You know, just as we explored new ideas that XState and state machines and statecharts enable. So we have the visualizer, which you could visit at Stately..ai Fizz. We also have a registry where you could store and share your machines that you create in the visualizer or in the editor. And so this editor is something that currently is enclosed. Beta preview but it's something that we are going to be opening up for preview, later next month, so late January, um. And so this is going to be an editor that allows you to visually create, state machines, pretty easily. And so the code that you get from here is going to be something that you could exports to X8 code.

And in the future, you could even, you know, use it to author, CI, CD pipelines, GitHub actions. You know, maybe even put mock-ups here. And, you know, just render your app or simulation of your app inside. A whole bunch of cool things are possible with this and I'm super excited about this editor. We've been working really hard on it. So, yeah, keep an eye out for that. But yeah. Also, the overall goal of XState is, and Stately, and everything that we're working on is that. The current state of code right now is that we really have to, look through logs and just tribal knowledge to understand how everything works.

Play from 24:00

27:00 If the documentation and diagrams change, of course…

And so improvements on that are just writing documentation or creating diagrams, but those quickly go out of dates. Because as soon as the code changes, we have to change the documentation of the diagrams. And if the documentation and diagrams change, of course, the code isn't going to change automatically. And so that's why I strongly believe that the ideal state is these executable diagrams, or visual formalisms, as David Harel, talked about. Where the diagrams that we create become an integral part of the code that we write every day. So that's what we're working on. And I want to thank you so much for listening to me and watching me here online. I'm David K. Piano everywhere. And we're also at Discord..gigi Xs if you want to join our community. So thank you, thank you very much David [Music] you.

Play from 27:00

Related talks