Lesson Description
The "Refactoring Reducer with Action Type" Lesson is part of the full, React and TypeScript, v3 course featured in this preview video. Here's what you'd learn in this lesson:
Steve demonstrates refactoring counter actions and simplify dispatching actions. He demonstrates the process of updating the code to handle different actions and payloads, ensuring type safety and error prevention.
Transcript from the "Refactoring Reducer with Action Type" Lesson
[00:00:00]
>> Steve Kinney: So now, I will refactor this slightly, where we can, we've got count and dispatch. I am going to make sure I have exported, yeah, I exported counter action. Right, and let me just close the tabs that are in the way. We can begin to refactor this is again, dispatch is really action dispatch with the counter action in this case. So we'll go ahead and we'll actually say that this will take a dispatch that is import that.
[00:01:03]
Oh right, this will now take a dispatcher that will always dispatch just this counter action, right? So now what we will do instead is, uh, simply say, ooh, typing. Prevent default on that real quick and we'll do uh, good. Oh duh. Properties need to be objects right, I could say in this case, this will be set count. And it knows that there should be some kind of a payload, which should be our draft count in this case.
[00:02:08]
And like, again, forgetting it would cause an error. Trying to give a number to increment or decrement would cause an error, right? And so now I can simply I've got this, great, there's not actually even like, I don't even need to worry about all that stuff with like, the event handlers and stuff like that, as long as I pass it in, the ability to dispatch actions, right, it will then have that and we'll get all the typing, all the stuff that it's allowed to send, so on and so forth.
[00:02:39]
Uh, the same here, literally, I would probably assign this to a type too, so I might say like, so we'll say that this can take this as well. We'll actually paste this in here. Dispatch, and now these just simply become. Dispatch type, oh, look at that autocomplete increment, easiest refactor ever. Payload is, oh, actually, there's no payload. I can just literally dispatch increment.
[00:03:35]
What are you angry about? I'll look at that in a second. Let me just finish, because too many red squigglies. We know. Can I put my coats in there. And that's not even the right place to put that. I think you need to swap increment and decrement too. Always, every time. But I've like used this example in other courses and also still made that mistake.
[00:04:39]
Uh. Also, there's some extra, so let's, let's, let's fix that. At one point, I should just move the buttons in the other order. Why are those angry? Quiet and type checker in action. Think what I need to do here is say that this is actually on the base class optional since in a lot of cases is legit not used. I need to figure that in a second, but I'm also figuring out why all my brackets are the wrong color as well, and we'll delete these.
[00:05:41]
Uh, do I have the right counter action? I do. Is there an extra set of parentheses? Uh, I think we're good with the colors. Right. Um, I was just saying that payload is still missing. Yeah. But I might take a second and just look at like where I made one tiny mistake while I was talking, but we'll. Uh. Oh, do I need to follow that thought all the way through, perhaps.
[00:06:40]
There we go. Right, which is I'm saying it can't be anything, but it is mandatory, which did make things confusing, right? Um, but now theoretically, we can just now, that is a very easy type to then pass around. We can say like, hey, here's a dispatcher, we don't need to pass you any state, we don't need to really worry about anything, and we begin to simplify stuff down.
[00:07:07]
There's a few points I have here, which is like the discriminated union pattern is useful for reducers. It's also super useful if like, um, you have various components in your design system, component library, or honestly just utility functions that take different like collections of arguments depending on what some of them are. Like this same pattern will work for like the worst thing that ever happened to the web, and we blame designers for this, and I love them with my heart and soul, is the idea that a button can sometimes be a link.
[00:07:41]
Right, and takes very different attributes from a button versus a link. So like, techniques of like what collection of properties it takes, this works in a reducer, we'll see it work later, we'll do the button link thing in a little bit, like towards the end. Um, it's a pattern that works lots of places, but like, if your brain hurt when we're trying to like, oh, it's actually going to be this, um, event handler, so on and so forth, right?
[00:08:07]
We just say if it takes this type, it takes the ability to dispatch it. We kind of use some features of React. To make things that in TypeScript might have been complicated a little bit easier, but then some of the like promises and guarantees that we have in TypeScript allow us to like be very confident that there's not some other case that we didn't hit, right?
[00:08:43]
Cause even if we gave this a like, bogus action, extends action. Type. Bogus and we toss it in to the set of actions it's allowed to take, we get yelled at again, right? Um, and it's like, yo, you handle increment, you handle decrement, you handle set count, you didn't do anything about bogus action, which means we could theoretically return undefined, which is not the promise that you made about what this reducer does.
[00:09:12]
Right? Um, and so you weren't exhaustive and everything, thereby we have a problem, and those are the subtle bugs, particularly producers, if it fell through every conditional that you had. You click the thing, nothing happens, or it immediately turns undefined, and those are the ones cause no error gets thrown, cause technically, your code is working, it's not doing what you want.
[00:09:34]
But the code works, you don't get an error, and that's those are the bugs where you lose a morning of your life that you will never get back. And now I am confident that every case has been handled here, right? I will get like, it will know that a payload is a number if it's set count. It will know that I cannot have a payload, right, just to kind of make that point one more time, if I tried to do a payload here.
[00:10:02]
It's like, yo, decrement doesn't take a payload. Right? So now somebody cannot accidentally assume that like, oh, what if I give it a number, and then I should decrement by 2, right? And that's fine if that's how the code works. Right? And like you, these are all numbered, but you could say, you can have to take, you know, the action type could be set error, which might take a different set of properties in that payload.
[00:10:27]
It could be error message, error code versus set success might actually have the data structure that you want, right? And then if you have one that is type error, it will know that it can't be the real thing, right? And if you have one that is the real thing, and know that it can't have an error message, right? And you will just get told in case at some point.
[00:10:47]
In a very complicated and large application, things are not working the way you expected, you will now very quickly get a red squiggly line somewhere, whether it's like in the sidebar or like in the code, or when you just run like npm run type check or whatever you call the like script to do that, or your CI/CD something will catch it, and then you will not get paged at 2 in the morning.
[00:11:12]
Right? And along the way, you'll get better, better autocomplete. And like I said before, I would be remiss if I didn't say like that thing that's doing a lot of autocomplete for you too, also can read these type hints and get a sense of like, what the right choice should be. So if you're like vibe coding adventures are not going the way that you want, perhaps getting a little bit better with your types will aid you in that endeavor.
[00:11:45]
Uh, some, um. Is there a reason why we're? I guess defining type and payload within action if we could also extend it into an interface and make more like defining, uh, like basically type and string are currently in action. Is there a reason why they would need to be if we could also just, I mean at this point, like in insofar that they are defined literally everywhere, I could theoretically.
[00:12:10]
What I would probably keep the action around for is like, across all of my reducers across all of them, they should fit this general shape, right? But in this case, insofar that they are all the same, like nothing really changes because it's still exhaustive, right? But I wanted to check to make sure I had type and payload. And maybe a meta, having that on the thing that they all extend also let me know that they do also conform to the right shape.
[00:12:37]
Right, these happen to all work cause I can see them all, but you can imagine even sometimes having that one just action. Cause you're, all this code could be spread out. And it gives you just one more of like, this one isn't like, let's say for instance, you, and I do in my actual codebase, I will probably never use just a primitive as the payload, it's probably an object with some keys and a value, right?
[00:13:13]
So if I said, uh, for instance, um, and we said type is a string of some sort. And payload let's just say it's going to be a record of string, and I honestly don't even know what the values might be, all right, like. Now I can't have, and if they were extending for me again, I couldn't have a payload that's a number, right? So if I wanted to make sure that all of my actions throughout my codebase fit that like shape, I could then use this as one extra layer of enforcement.
[00:00:00]
Right, and if somebody tried to make one that would behave differently than the rest, we'd catch them. Right, um, and we would know, and then we would tattle on them.
Learn Straight from the Experts Who Shape the Modern Web
- 250+In-depth Courses
- Industry Leading Experts
- 24Learning Paths
- Live Interactive Workshops