Managing state in a UI is challenging. It's genuinely difficult and the solutions require a depth of knowledge and experience to understand. Everything is a balance of tradeoffs in complexity, performance, and user experience. In this interview, Joel and Matt discuss those challenges and big ideas that drive React State Management in 2021.
Joel Hooks: [0:00] Hey, Matt.
Matt Pocock: [0:01] Hey, Joel. How you doing?
Joel: [0:03] Doing very well actually. I'm excited. I'm a state management nerd. I think that state management is such an integral part of, particularly fine web development, but probably all web development or application development in general.
[0:19] I'm curious and I want to jump right into it and see how you define state. What is state in a web application if somebody's asking you?
Matt: [0:33] State is a description of change in a web application. It's things changing. If nothing changes on a web page then it has no state, or we think of it in React as props and states. Props being static things that you get from above, and states being something you need to manage, maintain.
[0:51] State is, especially managing that state, you're not only managing how a value might change over time or how it interacts with other values, but it's also as soon as a new feature, for instance, gets thrown at your app or more complexity comes in, then not only are you managing all the states that you had to worry about in the past, but you're having to manage the state along with all these new features and things.
[1:19] Not only are you managing change inside your app, but you're having to also multiply that change by the changes that are coming to your app. State is a cause of a great deal of terror for lots of Web developers.
Joel: [1:36] Where does the terror come from? Is it the multitude of choice? Is it just the evolutionary exponential change that potential for states that you can be in? What makes it complex? Why is it such a challenge or an ongoing challenge, and not what I would call a solved problem, perhaps?
Matt: [1:57] A lot of the issue comes from the idea that, especially states that change over time, the complexity is like opt out. By default, you're having to approach a lot of complexity quite quickly.
[2:14] Even if you have, let's say, the traditional idea of a couple of Booleans that change over time, if you have like an isLoading boolean and hasError boolean, eventually, you're going to reach a state where one of those is impossible.
[2:29] You add a third one to the mix, then you get eight potential different ways that those Booleans can be rendered. You add another one at 16. Unless you're choosing tools that let you opt out of that complexity, you're going to find yourself stunned by that eventually.
Joel: [2:46] I feel the Boolean is the minimal, it's the obvious place to go. We're thinking about, "Oh, well, this needs to be on or off," or, "I need this component to do this thing. We'll just pass in a Boolean." Then what you end up with effectively is a function and arguments where each one is some management of state.
[3:08] As developers, we have to go in, process that, and load it into our own internal mapping of the application or the slice of the application that we're looking at. When you grow that, it's fine. We start. It's like, "Oh, it's fine. We'll throw it in there."
Matt: [3:22] It's obvious.
Joel: [3:23] All of a sudden, when there's hundreds of different little switches, you've gone in. It's like having a wall of light switches, and you flip them on and off and which one affects which light. How does this work? What happens if I do this? They're multi-way switches, so one is off and makes another one on.
[3:40] The whole thing explodes into a big mess that nobody can hold in their head. You can't physically as a human. Most of us cannot hold that amount of complexity inside of our brains at any given time, so it cascades. That's been one of my ways of looking at it.
Matt: [3:59] All the complex bits as well, all the edge cases, the things you don't expect, the combination of those light switches that you didn't think about, those are by default enabled in your app. There's no way to turn those off with a lot of tools that we use.
[4:20] You have to end up writing very defensive programs, writing like, [laughs] "I will prevent this at any cost. However many if statements I need to make, I will stop this bad thing from happening," instead of it being not possible by default.
Joel: [4:36] The only time I've ever would describe this as fun as if you're creating generative art. That can be really fun. I have no idea what's going on, but it looks cool. For me, anyway, that's not the kind of application I get paid to build. People expect it to work in a certain way. That adds a lot to it.
[4:56] Over your career, what are some of the ways that you've approached this problem? What are some of the libraries or solutions or philosophies of state management that you've actually encountered?
Matt: [5:10] I'm thinking back to when I had to implement, like when you go on Netflix, and let's say you're on desktop, you hover over a video, and it pops out, you're in this array of videos, it hovers over and it auto-plays. A tremendously difficult thing to code, and I remember approaching it. This was about six months, I'd say, after hooks did come out and React, and I was working React.
[5:39] We didn't have a strong methodology for handling states. We used Flux at the time. It was an old code base that we were bringing hooks to, and it didn't feel right to put something that was so local into a global state, for instance. I've used Redux in the past, but again, this wasn't a global state.
[6:01] I couldn't find anything that matched what I wanted, that handled local component states in a way that felt complete. What I did in the end was hash together a bunch of user effects and a bunch of user reducers, and try to get something where it would work properly, and it sort of worked properly. Then, of course, you ship it, and it works properly, but it doesn't quite.
[6:28] New features come in, or new bugs get found, and the light switches go off, go crazy. In the past I've used Redux quite a lot in that heyday of React boiler plates when maxed over, when it was all Redux and Redux Saga, and that kind of thing, and found some similar issues there where maybe too much was being thrown up into the global scope.
[6:55] That's the typical thing with Redux, or the typical pitfall that people fall into. It was either throw things up in global scope and it will managed beautifully for you in an event-based architecture where all the tools will help you, or manage it in local scope and you're on your own. You just use the tools that React gives you, and theory should be enough.
[7:20] That's where I find XState very interesting, because XState is a tool that lets you handle local component scope in a way that's very beautiful, in a way that works elegantly. I'm leading you into something there.
Joel: [7:37] Yeah, for sure. It's interesting that you talk about the Netflix and their problem, and internally they refer to it as the list of list of movies, and it's an interesting stateful problem, and they use RxJS a lot or have in the past and handle that with streams and reactive programming.
[7:55] There's a lot of different interesting ways to approach that. RX and reactive programming, it's another solution. It's a very large sledgehammer solution, I feel like. If you're going to come in, and you're going to use RX, then basically you're going to use RxJS and you're building an RxJS app. It's one of those that feels like that. I want to talk more about XState. You mentioned it, and that's the theme we're going to get into.
[8:25] What XState is is a state machine library, and I think state machines, as the name implies, are well suited for managing all sorts of different stateful procedures and processes and workflows, and how the application should work.
[8:43] We've used them a lot in Egghead and the applications that we build. How would you describe a state machine broadly or generally? What's your pitch if somebody's thinking about using a state machine? How would you describe them?
Matt: [9:00] It's funny because I don't have a computer science background, if that makes sense. I didn't go to school.
Joel: [9:07] Me neither.
Matt: [9:07] Most of us didn't. You hear a lot of talk about state machines being like, "OK. Yeah, you'll learn this at computer science school, or whatever. You'll figure it out," and you hated them at school. The first time I learned about them was from David watching "Talk with David," and the way I'd describe them is like a reducer.
[9:32] A reducer can receive events, and it updates some state, except it's like a reducer but with superpowers, because a reducer, whatever event you fire it, it's going to react to that event, and it's going to change some context or change some states, or do something. A state machine lets you make only some events possible in certain configurations.
[9:58] Let's imagine that you have some state that controls whether your user can log in or not, they're logged in. You have two possible states, when you think about it. The user can be logged in, or they can be logged out. When they're logged out, we don't want to allow them to logout again.
[10:16] If we were using a normal reducer, that event would still be processed, the thing would still happen, and any side effects that come from that would be caused. In a state machine, you can say, "OK, in this state, certain things can happen, and, in this state, certain things can happen." You get to be opt in about the light switches that you enable in certain settings, and other things.
[10:43] The other thing that a reducer doesn't have that a state machine can have, and this is something interesting about XState, which is people call it a state machine library, but really it's a state chart library. State charts are a specific implementation of state machines.
[10:58] State charts are first theorized by the guy called David Harel in the late '80s, and they not only involve state machines, which are these different states where different events are allowed, but also they involve actions, and side effects, and waiting, and all of these things that are present in front end applications, but we don't like to talk about. All these things are not pure, let's say.
[11:26] You think of a pure function as something which takes in an input and renders out an output, a reducer basically. A reducer takes an event, returns a new state based on that event. XState and state charts handle side effects that are not pure, and they handle them in a native, interesting intuitive way.
[11:53] Your original question of how would you describe a state machine, a state chart, it's like a reducer that can gate certain events from happening and handle all of the side effects that your app could possibly produce.
Joel: [12:07] One of the most interesting aspects to me that you mentioned is that conceptually, a state machine has been around for a long time. State charts were formalized in the '80s, but I know David likes to describe, he says everything eventually becomes a state machine anyway. At the machine level, everything you build becomes a state machine, so you could embrace that or not.
[12:32] When we use a library like XState, we're embracing that fact. What makes an XState interesting is a library? Unlike others, there is not a lot of state chart libraries. There's a handful, but it feels like it's a narrow space, and XState is dominating that space because it's a good product, and it does the job really well. What makes XState, as a library or a solution, interesting that has you reaching for it?
Matt: [13:03] Great question. It certainly is the dominate space. Basically, it has David, who's one of the most vocal advocates for state machines out there, and he's been pushing this for a number of years and talking about it a lot, and thinking about it for a long time.
[13:22] It has him, and that means we built up this community around it, and that means what you saw with GraphQl when GraphQL got wide adoption, the tooling has started to build up around XState. We have the XState visualizer. Another interesting property of state machines and state charts is they're inherently visual.
[13:44] You can visualize some programs, but mostly you need to run the programs in order to visualize them, but with XState you can look at the code without even running the program and go, "OK. I can see that we have this state and this state. This event leads to this state." It means you can look at your program instead of needing to run it.
[14:07] That means that we have the visualizer, which is on the XState docs website. We have an inspector as well. This means XState inspects, which allows you to look at a machine that's running in your code. You've got a front end dev server let's say, and you've got a machine running, you can ping up the XState inspector and live look at the machine running.
[14:32] Not only that, but we're at the cusp of all of the tooling that could be possible around XState. I don't code history that well, but it feels in the last 10 years or so, we haven't had a good way of extracting visualizable introspectable content from our code that we can use in all sorts of different way.
[15:01] The next step is, David's going to be releasing soon, hopefully in the next couple of months, is a visual builder for XState. To be able to build these machines visually. Just like you use Excalibur or Whimsical or things like this, you can just build a machine and stick it in your code.
Joel: [15:21] When you sit down and you're going to build a component, and you're building a new system, would you sit down and start by coding the state chart or the state machine before you start the component? Is that something you've done in the past?
Matt: [15:35] I did this literally the other day. It wasn't actually for a component. It was for a database entity, oddly. It was for an accountancy firm, and the accountancy firm needs to be able to ask questions to its clients. The questions can be in a number of different states based on if they've been sent or not, or if they're not applicable.
[16:00] They can have certain events that are applicable in certain states. What I did was I put it in the visualizer, and I sent them the state chart and said, "Does this model match what you're thinking?" That's another interesting part of this is XState can be used on the frontend, and it's great on the frontend. It can also be used on the backend.
[16:21] It can also be used in backend systems. It's not necessarily linked to any one framework. In fact, Gatsby's build architecture runs on XState. They have all these parallel processes running in things, and they can see their own different states, and moving through is wonderful. What was the original question?
Joel: [16:43] Do you sit down, and is XState like a design tool, or more to the point, is using state machine or state charts a design tool? XState's an implementation of those.
Matt: [16:56] Yes.
Joel: [16:56] It's funny because I also think it's interesting because you say you're able to take that result. You're able to model that and model that activity and then present it to a client and say, "Hey, how does this look to you?" Talk about it, versus if you're showing them some typescript or whatever, it's not a conversation.
[17:21] I haven't seen anybody even discuss UML diagrams in probably a decade. It seems like they fell out of favor, but it's that kind of thing where you're connecting and saying, "Hey, look. Here's the workflow. Here's that data that's going to go through and the conditions that we see right now. Does that match what you're looking for, how you think about the problem?"
[17:41] That's interesting to me because you're modeling the problem space, and the transitions and conditions that make up a real-world problem. They need to have people that are doing this and know in that situation you can talk about design before you invest a lot of the code level, which can be super expensive for the client.
[18:02] I don't like building wrong things and then having to rebuild something that's less wrong, maybe. But yeah, that's an interesting design aspect and benefit of using state machines.
Matt: [18:16] It's even one step beyond that, because it's not only design, it's code. It's not only like UML, for instance, design something to show to the clients and then code gen something out of that, or reimplements it somehow. It's just code. It's just JavaScript. I was able to use that machine in the implementation, the backend method. I just used the thing that the client approved.
[18:44] I feel we're really at the start of something when it comes to that because I had to manually write that code out by hand, using XState's object syntax, which isn't for everyone. What I hopefully can do in the future will be to visually build that.
[19:06] Let's say you could even associate different things with different states. Let's imagine that you have a prototype, built-in SkyDraw or Figma, and you can say, in this state you're on this screen, when you press this button, this fires this event. Suddenly, you've got a working Figma prototype based on something that's going to power your code at the end of the day. There's so many possibilities here.
Joel: [19:31] That's interesting because it takes it into that Low-code No-code realm, which, I think, it's a natural evolution of building these kinds of applications. There's a whole bucket of applications where that is appropriate. As coders, we have good job security for a couple decades, at least.
[19:53] I'm hoping that's about probably my working life span. Hopefully, I can keep at it for a while. I love the idea of being able to empower more folks, so you don't have to have all this deep esoteric syntax knowledge that it requires to do high-code solutions. There's always going to be those that exist. Always is a long time, but it's a need to see that evolve.
[20:25] I do think XState, and State Machines, and that kind of approaches is logically a part of that. An example of that to me is Xtate Catalog, which is this project that you recently started, where you're taking machines that are designed around a common problems and giving people those as templates, as starting points, or even final points for some of them. Can you describe XState Catalog and how that project started for you?
Matt: [20:58] Yeah. What I noticed was, and this is an issue with learning lots of different things, is that the examples out there for XStates were mostly on the trivial end. Mostly on the intro, tutorial thing, the traffic light example, to-do list example. It didn't match what you would do in an actual app.
[21:22] The interesting thing about XStates is that you can express state in a schema, which can then be taken and implemented in lots of different ways. You can say, when I'm in the exiting states or logging out states, I want to go back to the login page, for instance.
[21:43] XState doesn't care how you implement that navigation. You can declare that it's going to happen, and then you figure it out when you implement it, local to a component.
[21:54] There's an opportunity there. I thought, XState machines are portable. You can use them in any framework, they can be copy and pasted, and there aren't that many examples of out there.
[22:07] What I thought was, I'll put together some of the machines that I've been using in production, or interesting little side projects, or interesting ways to use XStates, and stick them all together so people can look and interact with them and play with them. It's been a rewarding project so far. It's fun to see people, I saw one going to the Egghead GitHub the other day. You guys are doing a rebuild, is that right?
Joel: [22:33] Yeah. We've been working almost a year now. We launched it in January of 2021. We're working on managing, we appeal our teams, they have to add and remove co-workers from their team or whatever. It's a complicated process.
[22:53] There's some gotcha's, and we want to make sure, and confirmations. It's a workflow. It was a particularly XState kind of problem. We're using it in a couple of places, but what was interesting was we could go to the Catalog and it's, "Oh, look, I've basically described what we want to do, and we can take that." For us it was a great starting point.
[23:15] We had to modify it a bit, but that's fantastic because it probably saves half a day or a day of work, which is significant, and you start thinking about that and compounding it to, 10 people use this a week. The sheer volume of work hours where we can think about other problems or start addressing that was interesting to me.
[23:39] It's a neat project, even, I want to say cooler than that, but I like it as a learning resource because, like you said, the examples, it's like a light switch or traffic light example. It's fine, but here are all the things that you can do with this. I was thinking about it, and we like a tailwind UI, and we've been using that.
[24:04] One of the reasons I like tailwind UI, it's like here is all the common layouts that you're probably going to need. What if you can just cut and paste that as a starting point, versus every time we approach a problem we have to reinvent it from scratch, and that's so tedious. I don't want to reinvent, I want to use resources and then think about higher level problems.
[24:25] I love seeing something like this come out that allows that elevated thinking about our work and time saving. There's some correctness to it too, because we can take that work, pre-vet it, like, this will probably work.
Matt: [24:43] There aren't that many copy and pasteable solutions. We don't seem to like copy and paste as an idea. We prefer things to be bottled up in libraries, which you then import. We think, the library maintainer knows what they're doing, that code is set, and that's all good.
[25:03] Eventually you run into an issue with a library, and you wish, "I wish I had full control of that code." XState is particularly good at that because it's all there. All of its internals are exposed. There's nothing. You can delete the whole thing and start again if you want to. I'm glad you guys are enjoying it.
Joel: [25:24] It's like patterns. Instead of sitting down to a blank page, we start with a pattern. It's not that we can't add our own sauce to the pattern as we build it, but we start with a pattern instead of starting from scratch. That, to me, is extremely powerful, and that's what evolves into the Low-code or No-code solutions.
[25:47] It's like, here are some patterns. This is how people use this stuff, and here's how we can build it. We're going to connect those patterns and make it to where you can apply these tools and come up with new interesting implementations, but based on tried and true and well vetted patterns. w
[26:02] Which makes for stronger applications that probably run with less errors, and get shipped quicker and on time, and allow us to do more different stuff and think about different problems.
Matt: [26:17] Yeah, like painting over a sketch. You've got some guidelines to work from.
Joel: [26:20] Yeah, but is it art? I'm just kidding. [laughs]
Matt: [26:25] It's art if David says so.
Joel: [26:28] Of course it's art. I like that. That's a good answer to that. What's the response been? Have people been using it? Have you been getting good feedback?
Matt: [26:39] Yeah, for sure.
Joel: [26:39] Are you going to continue working on it?
Matt: [26:41] Yeah, for sure. Some especially good feedback, a lot of people want to take the underlying code that runs it and turn it into a storybook style. That's been the coolest feedback. You might have heard the Chakra UI are thinking about remaking a lot of their components using state charts, and exposing those state charts as public facing entities.
[27:08] You imagine trying to implement a combo box or something like that, and you go to Chakra UI and say, "OK, yeah. I'll nick that machine. That's fantastic." That idea that XState is portable is catching on a bit, which is quite satisfying. I like that.
[27:26] That is something that we may think about in the future, is exposing a storybook type tool for your machines where most of the catalogs are written with MDX, and you can do these clever things where you say, if you click this event, you go to this state, and it all lights up and looks quite pretty. Exposing that and having that as living documentation for your code that runs your code is an exciting proposition.
Joel: [27:52] Yeah, that is cool. You had mentioned to me previously about this idea of code gen or the potential for code gen around XState and state charts and state machines in general. I was wondering, what's the future of generating these going forward?
Matt: [28:15] State machines and state charts, if you think about it, is basically a schemer, and we know from other schemer type languages, like GraphQL for instance, that if you have the basic schemer of how something works, then it's easy to generate clever types from it.
Joel: [28:35] If you're using TypeScript or some other type language, yeah.
Matt: [28:37] Using TypeScript, or BuckleScript, or ReScript. You can generate types. You can generate all sorts of stuff. Let's go with the types for now. This is another project that I worked on, which is called XState cogen, which was an attempt to create perfect types around XState.
[28:58] The idea being that you could take a machine and run the code inside the machine and introspect it, and pull out all of the typing and pull out all of the actions, and all the various parts of it, and get absolutely perfect types for what was being called when. XState is complicated when it comes to type script. There are quite a few gotcha's.
Joel: [29:23] [laughs]
Matt: [29:23] There's a few little tricks you need to know, and we're hoping we can make it a better experience for this in the future. If you think about anything that can be introspected, you can generate things from. You can essentially turn a machine into a Figma diagram. You can turn a machine into a Excalibur diagram. I've even seen a project turn a machine into ASCII characters.
[29:47] You can have a common declaration right alongside your machine that visually shows what it is. Not only that, but there's also recently been a couple of attempts to create a DSL, a domain specific language, that's just for state charts, that complies to XState. There's one called Lucy Lang which is written by a guy called Matthew CP on Twitter.
[30:15] I can't remember his last name off the top of my head. Matthew Perry maybe. Oh, that's the guy from "Friends." That one, it basically compiles to XState, but it's a very user-friendly language, and I find that exciting role, XState as a compilation target either for a visual builder, or for these DSLs that are emerging. It's such an exciting tool space.
Joel: [30:41] For me, that's probably the hardest for adoption, because it feels complicated when you get in there, because it's a massive amount of configuration that goes into building a machine. You're in there, and the way it is done now is all through JavaScript Object, so it's a nested JavaScript Object builder syntax.
[31:09] I've used state machines across a few different languages for almost two decades now, and it's always been that way. That's how I've always built machines. You get into it and when you first encounter it, or you encounter a new one, and it feels overwhelming and confusing, and that's a significant barrier to entry.
[31:30] How do we reduce that and make it to where you look at it and it's understandable and you can consume it? Once you get into it, and it's like your brain gets used to the noise of the configuration, you're like, "OK."
[31:45] Then, when it's loaded in your head, it's easier to load in your head, and you can sit down and, "Oh, that broke. I know exactly why that broke, and we need to fix this." It makes the work so much less complex, but you have that barrier of complexity that people encounter, and they're like, "Whoa, this is adding complexity. This isn't helping."
[32:05] That's something that work like you're describing would help to alleviate, and maybe see more adoption, and this kind of paradigm introduced into more applications.
Matt: [32:17] It sometimes feels like when you're building an XState, the way that we're building state machine is now an XState is probably the worst it's ever going to be. It sometimes feels like you're configuring a YAML file or something, or writing a raw cloud formation template.
[32:35] It sometimes feels clunky, and a lot of work is going into that API to make it consistent and make it work. Once you get in there, and your brain adjusts to it, as you say, then you start thinking, this is starting to feel intuitive. The tools that are going to come out to make this so much easier, if you think of it like a compilation target instead of a first-class language, then it suddenly starts making sense, and you think, OK.
[33:16] When the visual builder comes out, I've seen a real sneak preview of it, and it's nice. I think we're going to be having a different conversation about how approachable XState is.
Joel: [33:26] Yeah. That's probably true, and I look forward to seeing more visual tools around it. What's interesting that you mentioned is that it's quite literally, what you're building is a schema. It has a purity to it, and the reason we can take that and then generate off of that schema is because it's consistent. It's a closed loop. It is a finite state machine. It's not an infinite state machine.
[33:56] It's finite, and that means that there is a start and that there is an end, and that we can map and traverse all of the possibilities of that, computers can. I think I'd have a hard time doing it, but we can use a computer to go through and analyze that structure, but you can do that in reverse too. That's the point of a visual builder is we can use that to create the end assemble, the underlying schema.
[34:21] Then what's cool to me there is that you could go in, and you still have access to the schema. You can drop down to that Low-level. We can drop down into the state machine configuration, but that doesn't have to be the default. That will help people with the cognitive load of understanding the overall configuration. I'm looking forward to that personally.
Matt: [34:42] The front you can edit it from both ends as well.
Joel: [34:45] Yeah.
Matt: [34:45] You can contribute at the code level if you want to, or you can imagine tools that target a running GitHub repo and make a PR from a visual change. There's so much potential. Also, the fact that it's a schema, and it's immutable, it will do the same thing wherever you put it.
[35:08] It also makes it very portable, which is why the Catalog works, and why a lot of the future of this stuff is going to be about reusable machines. One story that could be improved in XState is its modularity. The idea that you can take a module of XState and reuse it again and again, like pagination, or like a FEX request or something. It's going to get more modular in the next version, but that's something else.
Joel: [35:42] There's always something to do and improve. If you're up for it, I'd love to see some XState in action. Do you want to share some screen?
Matt: [35:55] Let's do it, yeah.
Joel: [35:56] Put in some code?
Matt: [35:58] Can you see what I see?
Joel: [36:00] I can.
Matt: [36:00] All right, great. I've got a little Create React App working. We're in typescript. On the right, we've got a little hello world. Let's just say, "Hello, Joel. What do you want to build, Joel?" What do you fancy?
Joel: [36:16] One of the strong use cases where we use it is checkout flows and forms. I feel filling out a complex form or even a simple form often results in some local state. I don't know, what are people reaching for? What is the trends that you've seen from the Catalog?
Matt: [36:39] It's basically multi-step forms. Multi-step forms are what people seem to go for. You think complex legal forms, or payment checkouts.
Joel: [36:47] Wizards?
Matt: [36:48] Wizards.
Joel: [36:49] [laughs]
Matt: [36:50] The wizards come together. Let's imagine a wizard. Let's imagine, authentication wizard. How's that font size, by the way? You want it bigger, or would it be OK?
Joel: [37:00] That looks good to me.
Matt: [37:01] Nice. We need to be able to log in. We need to be able to confirm password. Let's imagine one of those kind of those Cognito type flows where it gets you to confirm. Let's imagine a forgotten password state, as well.
[37:22] When you're thinking about a state machine, I've imported Xstate into this repo, I'm going to import createMachine from Xstate. When you're thinking about your machine, you need to think about all of the points in time that your machine is going to cover.
[37:38] You notice, by the way, we're probably not going to write much Frantanko for a while. We're just going to diagram our way through this function and our way through this app. Let's start by saying const machine equals createMachine.
[37:59] We're going to start by saying what states our machine can be in, and these are finite states. Given that we have these three here, Joel, what do you think our state should be?
Joel: [38:15] This is always interesting to me because you have the different tenses you can use for your state names. We have log in, confirm, and forgotten. Do you go with confirming if you're in that state? You wouldn't say forgotten passwording.
[38:39] That doesn't make any sense. Logging in? I'm actually curious. What's your approach or strategy when you're thinking about naming these things?
Matt: [38:51] When you think about these three things, when you think about what the machine is doing or what the application is doing, what we're doing here is, ou're right, the tense is correct, but I would probably say, showing log in form.
[39:04] Here, I would say showing confirm password form. It's verbose, but I like the specificity here, showing forgotten password form. We got our three states here. The syntax for describing events is what we call the screaming snake case.
Joel: [39:30] Screaming snake case?
Matt: [39:31] Screaming snake case. SCREAMING_SNAKE_CASE.
Joel: [39:35] Oh, OK. This old school Java const style.
Matt: [39:39] The fancy stuff, yeah. This is the convention I've adopted for talking about events. Now, we've got our three states, Let's assume that these three states cover all of our use cases for now. We now need to think about how we navigate from case to case, or from state to state. How are we going to get from log in form, when in fact, we need a state where we have successfully logged in, right?
Joel: [40:08] Mm-hmm.
Matt: [40:09] If we think about it, we're probably going to start by showing the login form, the user naming until they confirm their password. They may forget their password at some point, but we will eventually have a moment in time where the user has logged in. Here, we're going to finish with a logged in state.
[40:27] You notice the tenses. Here, I'm saying, "Now, we're doing something. We're doing something. We're doing something." When we're logged in, we have done something. We're done. What are the patterns of events going from here? What can you imagine is going to be on this login form that we might be able to do?
Joel: [40:50] We have the input, so usually username and password, so they'll be filing it in. validating. That would be something that we might get into, and then eventually they're going to submit it.
Matt: [41:06] Sounds good. Eventually they're going to submit. We're going to take that on submit login form, and we will do something with that. That's to be decided.
Joel: [41:17] Right now, we're just figuring out the event and what's going on?
Matt: [41:21] Exactly. One thing we can probably do for now is we can target logged in. Let's assume that when you submit the login form it automatically succeeds, everything's always going to be fine, and we're going to target logged in. To do, manage complexity later.
Joel: [41:38] Yeah, error states and all that kind of fun stuff.
Matt: [41:40] Exactly, we'll figure that out later. On the login form as well we will need, if the user forgets their password, we probably need a way for them to navigate to the forgotten password area too. Let's say, click forgotten password. We're going to target showing forgotten password form. For now, let's start throwing this up on the page.
[42:08] We've missed something here already, which is going to be crucial for our state machine. Which state machines can display a finite number of states. They can end, so you can have a complete state, but you also need to tell the machine where to start.
Joel: [42:24] Yeah, for sure.
Matt: [42:26] Which state do we need to start in?
Joel: [42:29] I'd assume we'd start at the showing the login form.
Matt: [42:32] Yeah, that sounds right. Showing login form here. Let's now implement this in our component down here, and what we're going to do is go, import from XState React useMachine. UseMachine allows us to use this machine that we've declared here and pull some things from it. Let's go inside here.
[42:57] Const, we've got our classic React Tuple here. We're going to go, state and send equals useMachine, machine, and we're pulling it down from up there. Here, what we'll do is we'll have what we can check now is, depending on what state we're in, we can show different things.
[43:21] If state.matches the showing login form, then we're going to show a little div with a h1 login form, and we'll also have a button which goes to the, click forgotten password. Forgot your password, a nice passive aggressive question mark, and we can see there that things are working nicely.
[43:56] I'm also going to go have a little pre, down at the bottom, and this pre is going to JSON.stringify state.value. This is going to tell us what exact state we're in. We're in the showing login form state.
Joel: [44:13] Is that something you typically do if you're starting with a fresh component and building a machine and working as a debugging tool to show you what's going on?
Matt: [44:22] Exactly. All I do is stick it there, or I'll stick it in the console. When we want to press, forgot your password, unclick. This is similar to a reducer, this syntax that we've got, use reducer here. You imagine this is a reducer, we're sending events to that reducer. Onclick, we're going to send an event of Type.
[44:51] I don't have my TypeScript working at the moment, but it's going to be of Type click forgotten password. Now, if we click that, forgot your password. We're now showing the forgotten password form.
[45:06] Now that we know we've got a basic implementation figured out here, let's go back into the machine, and let's figure out more of our complexity, more of our requirements. When we're in the showing forgotten password form, what actions do we need to take? What actions do you think could be possible?
Joel: [45:27] Typically, you're going to, what do you do? You're entering your email address and hitting send.
Matt: [45:34] Yeah. Onsubmit forgotten password. Where do we go from there? What happens on that state?
Joel: [45:44] I was wondering if the confirm password form, is that the confirmation that that's going to arrive? That would be another state, right? You usually get a confirmation after you've done that. Hey, check your inbox.
Matt: [45:55] That's right, yeah.
Joel: [45:56] Check your phone, however you're recovering.
Matt: [46:00] Yeah. You submit your email, and then you wait for the code that you get from the email. This means what we could do is we could represent this as another sibling state of this. We could say, showing forgotten password code request, or something, or we could go deeper then.
[46:30] We're in this state here, the showing forgotten password form, and this technically could represent this and this state. What we have is a nested state within our state. Let's imagine that we have a requesting email state from within here, and then we have, awaiting code. What that means is we start with the initial requesting email, and the user submits the email that they want to use.
[47:10] Onsubmit forgotten password. When they've submitted their forgotten password, then we can target a waiting code. In here, this is where we'll wait for the code, or rather where we'll wait for them to input the code that they receive through their email.
Joel: [47:27] Do you think there's an instinct to do everything at the top level versus nesting.
Matt: [47:32] What I'm thinking of here is I'm thinking of the beautiful state chart butterfly that's going to emerge from all this. When we go to visualize this, in fact, why don't we do that now?
[47:46] We can take this machine definition, here this beautiful schema that we've got, and we can head to XStates.js.org/fiz, and we can bung this into the machine here. This, by default, is a machine there. I'm going to copy the entire object in, and we can update it.
Joel: [48:07] Nice.
Matt: [48:10] Nice and big. We have this beautiful state chart here. We can click, forgotten password. Then we head into, requesting email. You can see that we're in this step immediately. When we come out of this step, when this is done, we may need to go back to showing the login form for them to enter their password again.
[48:33] You can see when you nest things, it makes them easier to grock. It makes them easier to compartmentalize and understand what's going on. How's that feeling for you in terms of charts and explanation?
Joel: [48:45] It looks good to me.
Matt: [48:49] Nice. How far do you want to go with this? Obviously, we could take this all the way to the end.
Joel: [48:55] I'd like to see how you do some from the Catalog. We've got this far, and we're building some stuff up, and that looks fine. Is there something in the Catalog where we could go grab this and get a head start?
Matt: [49:05] I'm sure we could, yeah. This is XState Catalog. We have a multistep form, which you can very easily grab. I'm going to change the layout a bit. This one will work, maybe like this. Yeah, that's nice. One of the features I want to add is to be able to pull this down a little bit. Maybe in there. That's better.
[49:27] We have this form here, which is based on a payment checkout or an Internet banking checkout. You're in the entering beneficiary state. You confirm the beneficiary. Then you're in an entering date. You're entering the date that you want the payment to be sent. Then you can confirm the date, and you go in this confirming state.
[49:45] This confirming state is where you're reviewing all the information and that kind of thing. This, by the way, is not the XState visualizer but the XState inspector. This is an actual running machine we're looking at. You can confirm and then it can error.
[50:02] Go back, confirm again, and when it's done, then you've reached the success state, at which point your payment has been sent, and all of your money has gone down the drain. We can take this form, and we copy it to clipboard. Let's do that.
Joel: [50:19] This is going to come with all the nice typing info. Is TypeScript the default, or is JavaScript the default? Is that something you've selected? I'm curious.
Matt: [50:29] Yeah. TypeScript.
Joel: [50:31] I'm all in on TypeScript for life at this point, personally, but I know that's not everybody.
Matt: [50:38] For me too. It feels, as well, it's easier to go from TypeScript to JavaScript. Eventually we may have JS examples where all the types are expunged and things. It's so useful as well. A lot of people have trouble with XState and TypeScript and having these examples nice and type safe is decent.
[51:02] Let's pull this in. Let's go, paymentwizard.ts. I'm going to copy that in. We've got a cheeky type error. I know what's causing that, so I'm going to expunge it. That's a weird little bug where one version of the sign. I think I left a comment on that.
Joel: [51:22] Yeah, we literally ran into that bug last week.
Matt: [51:25] It's an odd V4 typing bug. You can see here what we were talking about before is that a lot of this schema stuff here, it reads like a YAML file. It doesn't read as beautiful and clear as the other one. What I like to do when I see a machine like this is fold all the states, fold them all down.
[51:50] At this point, we can see we have an entering beneficiary state, enter a date, confirm, and then success. We can visit this in the confirming state and pull this out. Let's grab that machine, multistep form machine, and pull it into our code here. I'll delete this machine that we've had already here, and we can pull it in there, multistep form. We're in.
[52:18] You notice we start getting type errors here too. We don't get one here, funnily enough. I'm going to change this to, entering beneficiary. Call this beneficiary form. This send is now going to send a type of confirm beneficiary.
Joel: [52:43] I want to not skip over what occurred there because you had code completion in your state machine. That's the benefit like TypeScript is bringing to actually spending the time to type all of the config for your state machines. You get delightful things like code completion of string constants inside of the machine, which is glorious in practice. I want to highlight that.
Matt: [53:10] You look at, for instance, when you're declaring an on inside here, you can go, OK. What events are possible in this machine? Here are all the events that are possible, the ones you haven't declared already.
Joel: [53:20] Really useful.
Matt: [53:22] It's not too shabby, yeah. We even know the specific types of the events too. This confirmed beneficiary here, this is giving us an error because we haven't given it the proper payload. We need to give it the info, which is amounts, let's say 12 GBP sent as a bribe to Joel Hooks.
[53:44] There we go. Now, everything's happy. When we head over to our React app now, it's going to refresh. We're in the entering beneficiary state. We confirm the beneficiary and we go into the enter index data. Just like that, we've grabbed a piece of logic, completely portably, stuck it in our app, and we're implementing the frontend now.
Joel: [54:07] We switched domains. You'd have to go in. Confirming beneficiary isn't something I'd want to use, but you go on and you change the language up and move it around. You end up with a nice pre-formed template that you can go in, change, study, and use for your own uses. That's exactly awesome.
Matt: [54:28] There's nothing hidden there. It's all up to you.
Joel: [54:32] That's great. Also, the visualizer stuff, or the inspector stuff is fantastic. I love you can go in there, and you start clicking it. You're walking through workflows.
[54:44] That's powerful, and that's something that you could take now, hook up, and have running in your application, in your development environment, or product introduction too. You can use that and run your application effectively. Is that correct?
Matt: [54:58] That's right. If you're running this and your machine is running in your app, you can control your whole app from the inspector. If you click an event here, it will go into your application and power something.
[55:13] When I think back about the Netflix video thing that I was messing about with, I could have powered it all through XState, had an inspector running, and simulated the mousein events, simulated the mouseout events, and got everything working beautifully, regrets.
Joel: [55:29] Fantastic. Matt, thanks for taking the time out. I appreciate going through this and learning more about XState and the resource that you've put together for us with this Catalog. I look forward to seeing how it can grow and the contributions you'll get, because I also think it's an interesting contribution space for folks.
[55:49] I suspect you've done most of the work so far, but I don't think going forward, that's necessarily going to be the case. It's an awesome opportunity for people to come in, explore, bring in useful stuff, and contribute in an open-source spirit to the Catalog that you're creating.
[56:07] That's going to be awesome as well. Anything else? Any takeaways you'd like people to think about in terms of state machine.
Matt: [56:19] Watch this space, is an appropriate phrase because it feels right now, I've never found anything as complete a solution as state machines to address complexity in applications. It's funny, because in a lot of tools and frameworks, it feels like there's a lot of churn, the things that APIs are changing every few weeks, or whatever. There's always some new idea, which is the hot new idea.
[56:53] When you learn statecharts, you're learning something which hasn't changed in 35 years, which is a complete solution to everything you're going to encounter. We're at probably the ugliest points right now, in terms of composing them, in terms of building them.
[57:13] There's so much out there that's going to improve statecharts over the next few years. It feels we are at a tailwind in 2017 point. Someone's had this great idea. Now, we watch it explode.
Joel: [57:29] I'm here for it.
Matt: [57:32] Me too.
Joel: [57:34] I appreciate it very much, Matt, and I'll talk to you soon.
Matt: [57:37] Good.
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
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!