Check out a free preview of the full State Machines in JavaScript with XState course:
The "Nested States Solution" Lesson is part of the full, State Machines in JavaScript with XState course featured in this preview video. Here's what you'd learn in this lesson:

David live codes the solution to the nested states exercise.

Get Unlimited Access Now

Transcript from the "Nested States Solution" Lesson

[00:00:00]
>> Let's take a look at how we could add nested states into dragging in order to get the behavior that we want. By adding states, we don't necessarily need to change anything. And that's because our mouse move mouse up and key up the escape transitions are still going to be exactly the same.

[00:00:19] So let's add a couple nested states. So initially we're going to have a normal state. And this is going to represent the normal operation of dragging. So states, We're gonna have two states normal and locked. So, the normal states, we don't really need to have any different behavior, we just need to know when the shift key is pressed.

[00:00:52] So we could do, What did we call it? So nine, So you can see here, we have a keydown.shift, in a keyup.shift. So I'm just gonna copy these from the final JS. Basically, we're listening for key down events on the body just like we are for escape, except we're going to be doing it for shift as well.

[00:01:23] So we're gonna be doing the same thing, For keyup. So when we press Shift+Down, we get the keydown.shift events. When we lift it up, we get the keyup .shift event, and those are going to be sent directly to the machine. So we could go in between normal and the locks states.

[00:01:43] So on, keydown.shift, we go to locked. And in the locks states, on keyup.shift, we go back to the normal state. So let's take a look at what that looks like right now. So when we're dragging, you'll see that we have another state over here, dragging.normal. This dot notation is how we could specify these hierarchical states as a string.

[00:02:11] And so when we press Shift, we see that we're in the locked state. If you did that correctly, you'll see that there's a red line in the middle that only tells it you can only go from left to right.Obviously we still can't go from left to right right now.

[00:02:26] We need to add that behavior in there when we're in the locked states. And so that behavior is normally defined in mouse move when we are assigning the delta. Okay, so let's change or not change that but I haven't assign x delta because we only wants to assign the x value.

[00:02:49] So we could remove the y value, and then, in locked. We're going to override this mouse move behavior. So mousemove, actions. We're going to assign x delta. You could ignore this internal false for now. And so now when we drag it, and we press Shift, now we're only able to move in the x axis.

[00:03:22] So we see that everything is working. Now, states can transition to other states directly even if they're nested. And the way that you do this nested state is by using dots notation. So right here in idle when we start dragging, we immediately go on the mouse down transition to the dragging states.

[00:03:48] And because we're not specifying a child, we go to its initial state which is normal. But we could override that, we could say dragging.locked. And so now ,when we start in idle we're immediately in the lock state, which isn't very useful, but that just demonstrates how you could go directly to this trial state instead of to the initial state of the parents state.

[00:04:13] All right, so Matt asks, Is there any issue with combining both the key up. And the key up listeners on the voice of both of them the shift and the escape, using a switch to determine which send events to send. There is no issue with that and you could definitely do that if you want.

[00:04:32] Again, it's up to how you structure your app. So, what they were saying is if we take this and we move it over here. Now we have one less event listener and everything should still work the same, I believe. Maybe not because we got rid of yeah, [LAUGH] targets target dragging.

[00:05:03] So now everything should work the same. Yep. So yeah, in short, you could definitely combine both of those. And there's not really any issue there because what you're doing is you're just choosing which specific events to send. What you could also do is you could send this events directly, you could say service.send(e), where e stands for event over here.

[00:05:28] And what you would have to do then is use guarded transitions in order to determine what should be taken based on what's inside the event. And so sometimes that's a good idea, but sometimes when you know exactly which events you want to limit to, then maybe it could be a little bit verbose.