Check out a free preview of the full React and TypeScript, v2 course:
The "Typing Reducers" Lesson is part of the full, React and TypeScript, v2 course featured in this preview video. Here's what you'd learn in this lesson:

Steve demonstrates how to use a reducer instead of setting the state directly. A simple reducer is created at types are added to the reducer's signature.

Get Unlimited Access Now

Transcript from the "Typing Reducers" Lesson

>> We talked about useState. The more other built-in way to manage state in a React application is useReducer. And as I alluded to several times, useState is just an abstraction of a useReducer. So we can argue that there is really one way, I'm not here to argue today.

[00:00:19] But how is that different? And I will tell you a story before we get into this, which is originally I was gonna start a new app, and then I was gonna let you implement it in the counter that we were working on before. And I think I alluded to this earlier when I was just building out the example first and with a bunch of any types, and then I was like, watch me fix it, right, or setting up for you to go fix it.

[00:00:46] And I was trying to test to make sure it actually worked before you fix the types. I was like why doesn't this work? And I was throwing console logs in places. And I was like, what's even going on? And then I realized that I had made a small, little mistake that wouldn't have happened if I was using TypeScript.

[00:01:04] And thereby realize that I'll use that as the example and then I'll kind of send you on the way with the original one I was gonna show in a brand new app, which it'd be fun for everyone involved. But let's do the simplest version first. So useReducer, if you've ever used Redux or even seen it, it's the same.

[00:01:25] usereducer is like Redux light, light, light, right? So no middleware, no dev tools, not all the batteries kind of included, particularly Redux toolkit now existing. It's not necessarily, but it's a nice, easy light version, I will a lot of times reach for it. If I have to put one useState in a component, fine, two, okay, five, no.

[00:01:52] At that point, it's a great way to say a thing happened, especially if I have to coordinate, changing this should then change this other thing. I will at that point say, this thing happened, right, and have some logic that is easily testable to make sure that the end result comes out, right?

[00:02:07] And so when things get a little bit more complicated for you, then useState makes it easy, then I'll go grab useReducer. Now talking to some people during the break, I know that not everyone has used this, so let's look at the world's simplest version. And so the world's simplest version, which I will pull in to the app in a second, is basically what useState is under the hood, right, simplified a little bit.

[00:02:34] But the way to think about a reducer, it is simply a JavaScript function, right, that takes two arguments, the current state of the world, a thing that happened. And it takes those things into the function, and it returns the new state of the world, right? Now there's a lot of things that we do, but the world's simplest version is, this current state of the world is that there's a count.

[00:03:02] The new thing that happened is that now there's a new number. The thing that comes out is the new number, right? Update the state accordingly, and then the hook's like, figure all that with the underlying link list and fun stuff like that. So this version of useReducer is effectively an analog to setState, in so much that let's just drop it in and we'll kinda just see it in action.

[00:03:33] So we got pull in, yes.
>> If you are using Redux, is it still worth using useReducer?
>> So my general rule, that's a great question, is that I try to think about state in my application in a number of different ways, right? So for instance, there's the true data application state, right, which is what blog posts or whatever, what are the things that I have loaded in my application?

[00:04:00] What is the editing state? Then there's a bunch of state that I think about, either view layer state or I call ephemeral state, which is kinda like, hey, is this accordion open or close, right? Which I do not need to store in a giant data structure that then causes re-renders throughout my entire app that I then need to cache and memorize, right?

[00:04:20] And so there's a world where I am using Redux for my big, real application state of, yeah, what models do I have loaded up for whatever we're building, right? Got that open Redux but stuff of like, is this form valid, right? That's really just on that view layer thing, right?

[00:04:41] And I might still use a useReducer for that, cuz checking to see if all the values in the form, that's probably 7, 8, 10, 15 new states. Yeah, that's still not necessarily worth keeping that form that hasn't been saved in the store, right? So I will still use it in that kinda middle ground of not necessarily worthy of being in the Redux store, getting a little ridiculous to do it in useState, right?

[00:05:05] But this one is ridiculous because, effectively, it's useState but I had to write my own implementation of useState first. But it still kinda make the point about TypeScript first, and then we'll then do it to a more real example with useReducer. So this just being a JavaScript function, right, in fact, if I wanted to, unlike useState, you take this, I mean, you could do it as function callbacks in useState as well.

[00:05:34] This is just a JavaScript function, it can go in a file somewhere else. I can write up a bunch of unit tests, pass a bunch of stuff in, look at the return values, so on and so forth, right? And as you can see, it automatically knows where to return your number.

[00:05:49] I could be explicit about that if I wanted to, right? And that way, I can't accidentally return the wrong thing. And so we say useReducer, we pass it this function that has a return value of a number, and that means it's a number, right? And yeah, just to kinda show you the way this works under the hood, I don't know, ReducerState, Michael, you have to remind me to delete this.

[00:06:12] So we have this and we say, All right, return type is a utility type we'll see in a little bit, and then we're grabbing the type of this reducer function. So type of reducer, as you can see, takes two numbers, returns a number. We're just getting the return type of that type, and so ReducerState is just a number, right?

[00:06:39] And so it is using that mechanism to figure out what count should be. And then setCount is react.dispatch number. So someone asked in the chat earlier, is there an easier way than react.dispatch and then open angle brackets react.setState and then number, like this, right, especially if you pull in dispatch?

[00:07:04] It was pulled in from React. I wonder if it automatically updates here. Yeah, it's just Dispatch<number> now, right? So that's a lot easier to pass through than all that other ceremony with setState and all that other things. So this is an easy type to just call out, and we'll actually do that in a little bit as well in the secondary app.

[00:07:31] And so it is simpler to pass around. Yeah, you have to hold its hand a little bit more, but especially when the complexity of, I have multiple values. The next app that we're gonna build is a color palette. So you've got hex codes and RGB values and you can change the RGB and it will change the hex code, right?

[00:07:46] There's enough of wiring all that together. But there's a super powerful pattern, Redux aside, of the state of the world, a thing happened. Figure it out inside this function and let me know what happens, right? Whether you use Redux, whether you use useReducer, the pattern itself also just works when you're writing just regular JavaScript functionality, and it's super powerful.

[00:08:11] And so we've got that in place. And so that is, we can see that basically all the types in React behave like they did with setState, which is not surprising given the fact that I've repeatedly mentioned that setState is an abstraction over useReducer, so we shouldn't be totally surprised.

[00:08:25] But that is some of the mechanism of how it works. Now, this is a ridiculous reducer. That said, there are versions of this that I have written before, right? I could, for instance, have a useState for firstName, a useState for lastName. And then when both of those change, listen to the other one, or I can have a reducer that has an object that has firstName and lastName, takes them both and spits out a fullName, right?

[00:08:53] Stuff along those lines where either parcel is changed, right? The moment you are deriving state, reducers aren't bad. Okay, so as you can see, this all kinda works. setCount works as expected, if you don't believe me, we can try it out. At this point, it actually should take a number and returns void, cool.