
Lesson Description
The "External State Management Exercise" Lesson is part of the full, State Management at Scale in React & Next.js course featured in this preview video. Here's what you'd learn in this lesson:
David instructs students to refactor a complex multi-step form with a large reducer and context setup using a third-party state management library like XState Store or Zustand. He also walks through a solution, including creating a store, defining transitions, using selectors to access state, and dispatching events, ultimately streamlining the codebase while maintaining functionality.
Transcript from the "External State Management Exercise" Lesson
[00:00:00]
>> David Khourshid: So what we're going to do is we're just going to take, let's do five minutes. And so in these five minutes, what I want you to do is take a look at the page in exercise libraries. This is actually a pretty big, it's a pretty big multi step form.
[00:00:23]
It is much bigger than the one that we've done before where you could enter a destination like Minneapolis, you could go today, I actually went yesterday. So number of passengers, you could search the flights so you see all of the available flights, you could go back, you could select, then you would search for a hotel, checkout date, search for hotels, et cetera.
[00:00:50]
So it's really a giant multistep flight form. And then you could eventually confirm your booking and then you go there. So as you can imagine, we have a pretty, pretty big reducer that's helping us manage all of this. And then we also have to manually set up the context, which, that's a lot of boilerplate.
[00:01:13]
So in these five minutes I just want you to play around with either XState Store or if you have another third party state management library of choice like Zestand, I want you to just get a feel for how you would refactor this to use that third party state management library rather than relying on react context and use reducer.
[00:01:39]
All right, so let's talk about using third party state management. In this example, like I showed you, we have a giant reducer and this, you know, comes with a lot of baggage. We have a lot of, we have to use context, we have to pass it down. There's a bunch of boilerplate.
[00:01:59]
And let's say that in your team, you decide that you want to abstract this into a third party state management library because you might have performance issues or you might want to reduce the amounts of code that you have to maintain. And especially with raw hooks like useReducer or use context, there's a lot of room for developers to make their own abstractions or their own patterns that they just hope that the other developers will be on board with, even though it's usually the case that they're going to end up disagreeing with each other.
[00:02:33]
And then you have multiple abstractions in the same code base. And this is another reason why I think third party state management libraries are great because they provide an opinionated approach to, to managing this kind of states. So taking a look at our booking reducer, I'm actually going to split the screen here, but we, this is a common theme.
[00:02:54]
We are going to be doing the same thing that we've done in other exercises where we're doing things side by side instead of doing a wholesale replacement of it. So instead we're going to have in this case a booking store. And we are going to create a store.
[00:03:13]
We're going to have our context and our context is going to be that initial state. So it's going to be the same as the booking state over here. And then we have all of our transitions that we could do. So just to show you one, as an example, we have flight search updated.
[00:03:32]
We get the context and we get the event. Sorry, the event is going to have a payload and that payload is going to be. This is where making explicit types really help. So we see that the payload is over here. There's a couple of ways to bring this out.
[00:03:58]
We could either just have a type flight search updated events and just pull it out over there, or we could derive that type. So the way we would derive it. So I'll just do it here. So flight search or flight search updated events payload. But the way that we could derive it, if you don't have this separated out into a type, is you could.
[00:04:30]
This looks a little bit ugly, but basically you could say this would be a booking action and you intersect that with type flightsearch updated and then you read the payload from that. Again, a little bit ugly, but that's why it's good to have just some more explicit types with that.
[00:04:51]
And then you're going to update it like this. And then you could do this with the rest of the actions you have, just converting them over. And again, we're doing things side by side. So we have a convenience use booking hook that we could use. And so this is where we could actually just read in the store.
[00:05:16]
Yeah, read in the store context. So we could say const storecontext = useSelector. Then we're going to be reading the bookingstore and reading in that context from there. So this context, confusingly enough, includes both the state and the dispatch. So what we want to do is, you know, we want to have the.
[00:05:53]
What do we wanna do? Yeah, so we want to do our console log. So we want to say console log store context. And we also want to compare it to the context.state. Again, I know that's a little bit confusing, but the reason that we do this is that when we're working in an application where we're doing this kind of refactor, we want to see that everything is still pretty much the same.
[00:06:22]
So for example, if we are entering our destination we want to see that the. Oops, let's see what I did wrong here. Store context. Wait, that's, there we go. Okay, it's giving me a whole bunch of junk. But we want to see that essentially both types of states are exactly the same.
[00:06:50]
So in this case we have CurrentStepFlightSearch, CurrentStepFlightSearch. And once we start doing things in parallel, we could see that the states match up. And so once those states match up, that's when we're going to be able to confidently remove the old implementation and replace it with a new implementation.
[00:07:13]
So I'm just going to show you, for sake of time, the end result. And so we no longer have any context, just fold all. So we no longer have any context because we're just bringing that directly in from the store. And so you could see that, you know, we have the step, we're reading it directly from the booking store over here and it has everything that was in our, our original reducer just like that.
[00:07:47]
So now instead, again, instead of using context, we use selector, grab it from that booking store, which we could put in a separate file, import that, and then we're reading the state and only the state that we need. That's the key difference here. And then on things like handle submit, we could trigger the search flights event and pretty much everything else remains exactly the same.
[00:08:11]
So we're using that pattern of selecting from the store and then dispatching or sending an event. And so this is going to actually be pretty much the same approach. Whether you use Redux Toolkit or Zustand or XState Store, you're replacing that useContext useReducerdance with a third party state management library.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops