Transcript from the "Wrapping Up & Q&A" Lesson
>> Steve Kinney: And so there's a lot of things for you to kinda think about. Can you combine these two, which approach is right for you? And I think it matters, you can use both in different parts of your application, right? You don't necessarily have to choose one. In either of these, we use both basic React component state as well as the ability to put stuff in either Redux, or MobX, or something along those lines, right?
[00:00:32] You can put all of that in place. Do you maybe wanna have the ability to have actions and reducers that modify MobX objects instead of doing it by calling back and forth? You could totally do that as well, right? You can mix it up with React hooks. There's a whole bunch of really interesting ways you can take these different things in place, right?
[00:00:56] Couldn't you make middleware that uses like async/await to do stuff instead? Maybe, yeah. Could you have the ability to roll back an API request, right? Like in how you do stuff with epics, right? There's a bunch of interesting ways that you can mix and match these ideas. And some of them, we could go into them here, but some of them will be very unique to what you need to do your app, right?
[00:01:19] And so I think that between Redux and some of the different ways of dealing with asynchronous code, I think Redux Observer was super cool. We use MobX in smaller parts. If I'm starting a prototype, I'm probably doing it in MobX. The reason that we chose Redux is because we understood it at scale, and making those changes are scary, and I'm risk adverse, right?
[00:01:43] So we went with the kinda path that we felt more confident in. We didn't wanna get to a point where we messed up our dependency graph, right? Have you go, hey Product, we need a few sprints to undo some poor choices that we made. I knew the patterns with Redux really well, and so despite the fact that we do use MobX in places of our application, and I'm a huge fan of it, right?
[00:02:03] And we were very much on the cusp, it was a debate. But just basically safety in shipping our product was part of it. And that's not to say MobX isn't safe, it was just that nobody had done a very large application with it, so we went with Redux.
[00:02:17] But like I said, we still use MobX in certain portions where doing that whole flow doesn't make sense. And the context API that is in basic pure React was only a month old when we had to make the choice. So it was one of those things where we didn't know at the time, right?
[00:02:35] I think the context API is also great, but the time-space continuum is also an issue that informs. You're gonna make a choice, and maybe some hot, new library comes out tomorrow. I think that as long as you understand some of the trade-offs on some of the approaches for doing these things, you can begin to mix and match some of them.
[00:02:54] The kind of word of caution that I'll give is, you know the kind of lay of the land, you know some of the trade-offs. When possible, giving yourself really good abstractions, right, and giving it so that you call this method that's gonna say, add an item to the list.
[00:03:06] You use that function, add an item to the list, all over your code base. If you need to change the fundamental way that an item gets added to a list, you change that one function, right? The second you find yourself repeating yourself and kind of doing squirrelly things all over the code base, it becomes a lot harder for you, right?
[00:03:23] So if you give yourself just functions that you call that do things with the data, you can make these refactorings. You can change your mind a lot more easily, right? But if you hard code a lot of the stuff in, you're kinda stuck with it, right? So the way that you think about these things can greatly impact your ability to change your mind later.
[00:03:43] I think I mentioned this earlier, we basically do all of our normalization in an adapter layer as the API requests come in, and we turn them on the way out. We did that actually not cuz we're smart about state management, we are. We did it because the APIs weren't solid yet, right?
[00:03:59] And we knew they were gonna change all the time. And I wanted the actual application to know nothing about the data we got back from the API. Cuz we were using brand new back-end technologies. We were switching from on-prem MySQL databases to stuff like Dynamo. And we knew that there were gonna be different trade-offs, you can't do pagination the same way.
[00:04:16] So we had this pattern that actually has helped us a lot. APIs change, we tweak one place about how we normalize our data, everything just works. We could switch to something totally different tomorrow, and it would all. I mean, it wouldn't be fine, we'd have to do some amount of work.
[00:04:29] But we would not have to rewrite the app, right, and that is, I can't sell that one again, right? So kind of understanding the concepts and being able to kinda mix and match them I think is incredibly important. All right, any questions?
>> Speaker 2: Yeah.
>> Steve Kinney: Yeah?
>> Speaker 2: So about structuring the data, you really stressed the importance of normalizing when you're talking about Redux.
[00:04:53] Would you say in the MobX side it's sort of completely unnecessary, or would you, what do you think?
>> Steve Kinney: Depends, if you're cool with the dependency graph, fine, right? But in a relatively small application, that's the problem with scale, right? Relatively small application, no thing you do is really gonna bite you in the butt.
[00:05:12] But as it gets larger and larger, if you're not thinking about it, right? And so the bigger your team is, the scarier those things get for me, right? Having those guardrails allows me to give juniors a lot of autonomy, right? Versus, in a code review, it's really tough, right?
[00:05:30] You look at that code review, and I've been the looks good to me on a code review that bit us in the butt three months later, right? I have done it. If you look at that code review, you look at the changes, this seems fine, but there's like cumulatively little things.
[00:05:45] This is where MobX State Tree becomes a thing that you can like, all right, I want the safety of an immutable state tree. I want a lot of the good stuff that MobX gives me, you can kind of mix and match those things. But yeah, the reason we went with Redux is because we knew we were really comfortable.
[00:06:02] We had been using effectively Flux for a really long time. We had been using a lot of stuff, so we knew it really well. So you're still normalizing your data to a sense. You're getting stuff into the API. That might not be how the MobX class looks like, right?
[00:06:18] So you're still gonna pull stuff from the API, you still might have to transform it in some way. And we even made a lot of computed properties, right? A lot of normalization is the ability to derive state. In Redux, that might happen in mapStateToProps. In MobX, a lot of the kind of rehydrating information was happening in those computed properties, right?
[00:06:39] So kind of where you do it kinda changes as well, if that makes sense.
>> Speaker 2: Yep, and then one other that's kinda going back to the basic React state that we talked about. So I know that you mentioned in the past that your app has undo, redo features, and that you use Redux, and it's really easy to undo and redo.
[00:07:02] But you also mentioned that you were thinking about maybe using context API. Wouldn't that make that difficult?
>> Steve Kinney: So actually, I think we kind of missed it. I'm actually gonna go, and let me see if I can find the slide where we talk a little bit about what undo, redo looks like in Redux.
[00:07:18] And what we're gonna find out is that as long as you're kind of using, particularly in an immutable state tree kind of structure, it's actually pretty similar no matter what. Just give me one second. So the way that you might implement undo and redo, and undo and redo is scary, cuz what are you undoing and redoing, right?
[00:07:39] The way that you might implement undo and redo, and you can do this in Redux, right? Theoretically, we can talk about whether you might even do it in MobX, right? It's if you hold onto the past, and you hold onto the future, and then you just kind of move stuff up and down a stack, right?
[00:07:58] The one meme of the course, right, is from Kylo Ren, let the past die, kill it if you have to. At this point, we're gonna do the exact opposite. We're gonna hold on to all past versions of the state. So one of the things that I said was really great about Redux and immutable state trees is the ability to kind of serialize the entire state of the world, right?
[00:08:21] And having that and being able to just completely replace something is incredibly powerful. So this is, again, if we were using maybe a to-do list or something along those lines. Well, when we might have otherwise just popped the item onto an array. Basically we can keep an array of all of the past states, right?
[00:08:44] That object of state, you pop it onto the past ones, you can kinda take the kinda present and be the what you return out right now. And if they did undo, you can take the current present becomes the future. Time travel is hard, right? Any time you have an action come into your reducer, do the context API, right?
[00:09:06] Context API, React nowadays has a hook called useReducer as well, so you can actually legitimately do this the same way. But any time you're calling the method, if you give yourself a good method, you can just, I'm gonna take the serialized object that's the state of the world now.
[00:09:20] I'm gonna put it on an array of past states, and I'm going to set the new state as it should be, and maybe future as whatever. Maybe it's an empty array. Should they undo, right? You take the current present, and you put it on the future array. You take the front of the past and make it the current.
[00:09:41] [LAUGH] And then you make the second-to-most recent past the most recent past. You're basically moving along. You could also do this with indexes. You can just basically move an index back on the array, or forward, depending on how you structured it, and play back and forth through it.
[00:09:59] So it's really actually about how you structure your data, again, like most things, and you can store all previous and past states. You need to probably figure out when they. I think the hard part of undo and redo, and just to show you what redo looks like. You're taking whatever is the most recent future that was the present, and putting it back, and just moving everything where it was.
[00:10:23] The trickiest part of implementing undo and redo is not the state management piece, it's the UX piece. What did they want to undo, right? Anything, right? How do they access it, right? Depending on what you need to undo and redo, it becomes slightly tricky, right, on a UX level.
[00:10:48] On a state management level, you can just, especially easy in Redux, a little bit less easy using pure React because you don't necessarily have the reducer pattern. But that context, when we looked at it in the prequel to this course, the React state course, right, we were using useState.
[00:11:03] But you could use a useReducer in there. You could mix having reducers and using the context API. These are not mutually exclusive, right? And arguably, you can implement your own versions of any of these, right? But yeah, having this thing where an action comes in, we return a new state of the world, allows us, gives us a hook to keep track of the last state of the world.
[00:11:21] And the state before that, and we just swap them out. It's actually shockingly simple, right? And that's effectively, we saw really briefly, I showed you the timeline in the Redux Dev Tools. It's basically behind your back, saving the previous versions and letting you step back through it, right?
[00:11:39] And so it's effectively an implementation of that.
>> Steve Kinney: Anything else?
>> Steve Kinney: That's a good one. [LAUGH]
>> Steve Kinney: Great, thank you so much, and good luck.