State Modeling in React with XState State Machine Solution
Transcript from the "State Machine Solution" Lesson
>> In this exercise, we are supposed to create the state machine to make the basic functionality of this timer work with the play button, the reset button and clicking the actual timer itself. And so we have three states. We have idle, running and paused. And so if we change this, ideally we have idle, running, paused, and this should also be a toggle as well.
[00:00:33] And so you could see that we're changing this up a little bit, but the state machine sort of looks the same. And from paused, if we reset, we should go back to idle. So overall, this is what our state machine should look like. Okay, so going back here, there's a couple things that we need to do.
[00:01:01] Let's go to the exercise. First of all, this is going to be a reducer instead. So just for now, let's do const, state, dispatch. And that's going to use reducer. And now we'll just have a dummy reducer right now in an initial state of whenever that initial state should be idle.
[00:01:29] Okay, so some errors state, return state. Well, we'll fill this in in a minute. Okay, so we have our machine in idle and by the way, we're displaying that state right up here. So, you could see the data state = state. That's the magic, data attribute that's actually putting that state right over here.
[00:01:59] And that's just a clue for just making sure that your machine is in the right state. Obviously, you could use console.log or whatever you want to make sure that as well. I like having things up here visually. Okay, so now let's get into our reducer. Because this reducer is going to be just like the previous reducer that we meet in the scratchpad, where we want to actually control a state machine that goes between each of those states.
[00:02:28] So again, we have idle, running and paused, and those are gonna be our three states. I'd like starting with the states first. So while our initial one is going to be idle, and we have states which is idle, running and paused. Now I like doing this because it gives me a nice overview of what are the possible states of my timer can be in.
[00:02:56] And then I could start filling in the details for each one of those. So, again I'm gonna do on and when we toggle from idle, we go to the running state. When we toggle from running, we go to the pause state. And when we toggle from pause, we go back to the running state.
[00:03:17] So it just goes back and forth between all of those. So we have our machine. I'm just going to shrink this for a minute so that you can see the full machine over here. And now we actually have to create this reducer here, which I call timer machine.
[00:03:33] And that's going to be the same thing that we did in our scratchpad. So if we go to scratch index.js, this exact same logic to going to apply for this too. And so instead of alarm machine, this is going to be timermachineconfig.states. So we're looking for each state, and then we're looking for the event that was sent to that timer machine.
[00:04:04] But now we actually have to send the events. So let's look at our, for example the click handler for here. This is the elapsed, which is going to be this time over here. Let's start with the play button actually. So, if we go to over here, this is first starting the timer and this we dispatch type toggle.
[00:04:29] And we're going to be doing the same for over here, the pause. And so now let's just make sure that that works. So you see idle right now, you click play. And nothing happens because we're still using our dummy reducer. So [LAUGH] we need to actually use the timer machine instead.
[00:04:50] And that's going to import that from timer machine. And we could also get the initial state over here if you wanted to, you could say timermachineconfig.initial. And that's also imported from the timer machine. Now things should work. So, I'll show you that again. We're in the idle state.
[00:05:10] You click play. It's in the running state. You click play again, it's in the paused state. So this starts flashing, and then you can toggle back and forth between running and paused. Now obviously we don't want this button to show if we're in the play state. So we could hide that by doing, we only want to show this by, and if it's not, yes, states not equal to, if it is the pause state, I believe and buy in.
[00:05:55] And so we could add the same logic over here. If state is not equal to paused, then we want to show this by now I believe that logic is correct. Let's just make sure. So play, paused, so this is if state is paused or state is idle, because we want to be able to start that.
[00:06:29] All right, I should remind directions more carefully, but we have play. It's in the running state. You click pause. It's in the pause state, and that completely disappears. So, that's weird. Okay, don't forget about your parentheses. So we want to put our conditional in those parentheses, and only then show the play, paused, play, paused.
[00:06:59] Now let's do the reset. We're gonna be doing the same thing. We're going to dispatch type RESET. And that of course should take us to our idle state. So if we're playing, and then we pause it and then we click reset. On the reset, we dispatch a type of reset, but as you could see, nothing is happening at that moment.
[00:07:22] So we have to reset. And on the pause state, and that should take us back to idle. So we click that, or sorry, we play. We're in the running state. We click paused, and when we click Reset, it takes us back to the idle state, which is the beginning state.
[00:07:44] And so that's the general idea of using a machine in your react components in order to control the logic. If we look at the final code here, basically looks exactly the same. And if we look at the final code over here, you'll see that we have our click handlers here.
[00:08:04] So we have toggle for elapsed. And, we're sending the reset events on the reset button, and we have the toggle on the other places as well. And so also one more notes. Right now we're controlling the visibility of our buttons based on which state it's in. This is great because it's a lot more clear than having a bunch of Booleans and having to wrestle around with those.
[00:08:35] You have a clear idea of when exactly those buttons should show. Instead of doing this 20 questions approach where you're saying, is it this? Is it active? Is it paused? Is it running? You could say, when the state is in the running mode or the running states, only then should you show this button.
[00:08:55] And also because the logic lives in the machine itself, if you accidentally forget to add this and you might have the button show, then the logic is still going to work the same. In that events that shouldn't be accepted in a certain state will just be completely ignored, which is exactly what you want to happen.
[00:09:19] So yeah, so are there any questions about this exercise so far?
>> I just found I had my stuff in0 the wrong state and it's like react, react only displays based on the data. So I thought I had something wrong. And I thought it was working and it wasn't refreshing or something.
[00:09:37] And then I realized I didn't have the right state set. So it was it was just kind of validation of how I react and state machines that gets to work in terms of it's not in this state, so nothing's happening, sir.
>> Yeah, and that's what I like about state machines too is that it's all centralized here.
[00:09:55] So if you have an error in your logic or something's not working correctly, then chances are, you could just fix it within this machine. Because your user interface just becomes a thing that could display the state, and send events. And when you reduce the user interface to just those two things, a lot of things become a lot simpler.
[00:10:17] So, yeah.