This course has been updated! We now recommend you take the React Performance course.
Transcript from the "Reducer Action & State" Lesson
[00:00:00]
>> You can see that when the page first announces the generating the fake name library, that is a third party dependency also likes to log to the console. So that's fun. But you can see that we render the new grudge component, we're rendering the individual grudges, that all makes sense.
[00:00:15] The page is mounting for the first time. What happens if I just forgive one grudge? Well, we end up Rendering New Grudge again, and all of the grudges in there as well, right? And that's not great. So we will deal with that using a pattern that we're gonna use multiple times in multiple different ways.
[00:00:34] So the rest of this workshop is this reducer pattern. And we'll see why we can solve this initial issue, we'll also solve the prop join pattern and put this initial issue back. And we'll talk about the tradeoffs there. But the use reducer pattern allows us to do some very complicated state management in a much easier way than if we tried to wire it all together using use state and a bunch of like custom hooks.
[00:00:56] So let's go ahead and just very quickly do the kind of first introduction to a reducer. A lot of times, reducers scare people, because I think I have this hobby horse, which is a lot of times the first time you come across reducer is a lot of times when you're using React, Redux, rather.
[00:01:13] And I think there's a problem the way we teach Redux, which is we try to teach Redux along with React, and the React Redux library all at the same time. So you're learning like four things at once and you want to cry. The actual concept of a reducer is super easy, it is a function.
[00:01:29] And it is a function that takes two arguments. It takes the current state of the world, right, which should just be a JavaScript object or an array, hopefully an object. Takes the current state of the world, and it takes a second object, it takes a second object here.
[00:01:46] I mean, you can put the state in and the state comes out, right? The second object that goes in is the action, right? So here's the current state of the world. Here's a thing that happened. It takes these two pieces of data and figures out what the new state of the world is, all right?
[00:02:01] And that is all it is, this is a simple JavaScript function. You could write a reducer function yourself, we will. And as long as it takes the current state of the world and an object that represents some thing that happens in the world, in both go, and only one thing comes out, which is the new kind of resolved state of the world.
[00:02:21] Now we tend to hook that up to our views, right? Okay, new state of the world, we're gonna give that two components, right? Here's what you need to render, here are the grudges, so on and so forth. Now, you notice that the grudges have a forgiven check box.
[00:02:37] Well, that's a thing that happened in the world, right? So when someone hits the forgiven checkbox, we dispatch an action like, hey, this grudge has been forgiven. Those two things go into the reducer. The state of the world, the action that happened. And new state of the world comes out with our grudge forgiven, right.
[00:02:54] And that's effectively what it is, in this case. Cool, so let's go ahead and let's see if we can refactor this application a little bit to use that. So we'll do this in application. Now, I told you, writing our reducer function, pretty straightforward, right? You're ready? We'll say const reducer.
[00:03:17] I'll write the world's simplest reducer function, we'll say state, action. There it is. Now, this one is very much like a teenager and so that it takes the state of the world, and anything that happens, it ignores it and just keep on doing what it was doing, right?
[00:03:44] But this is the very beginning of a reducer, right? And so that is it. It is simply a JavaScript function. There is no black magic here. It is simply a JavaScript function. Now, we can switch out this useState for a useReducer. Let me just add that, switch this out real quick.
[00:04:11] UseReducer, now useReducer takes two arguments. It takes a reducer, well that seems good, right, and an initial state. Now, that could be an array, it could be an object. I have that fake list of grudges with the autogenerated names. So I didn't accidentally, imagine if I wrote the list myself and it was somebody in the room.
[00:04:29] That would be very, those names are autogenerated. So if you see your name, don't take any offense unless you did that thing, and then own it. And instead of taking grudges, it takes this function called dispatch. We've got this ability to dispatch actions, right? We had to take out the setGrudges, because right now, we've removed that function, right?
[00:04:48] The app blows up because that's not a thing. But what we'll wanna do is dispatch actions and say, all right, when that actually happens, effectively doing the same thing that we're doing in each of these. But what this allows us to do is divorce the management of our state with the actual components that are rendering the state, all right.
[00:05:09] As it stands right now, with the use state, that is all happening inside of the component that is also showing the markup, right? And it works, and it's not bad, but it does kinda get a little murky with those separations of concerns. Here, we're gonna say, all right, we're gonna give you the state of the world that we're managing over in this reducer over here.
[00:05:29] We're gonna give you this dispatch function to say stuff happened. But all of the state management is going to get pulled out of our application. Now, there's a bunch of really great things that happen here. As we mentioned before, this is just a JavaScript function, right? As this grows and gets more complicated, it becomes super easy to unit test, right?
[00:05:50] You want to see what's going to happen? You pass a JavaScript object which is the state of the world that you're assuming, you pass in an object which is the thing that happened, and you make sure what spits out at the end of the function is what you thought, right.
[00:06:01] You don't necessarily need to mount all the components and do all that kind of stuff, because a lot of times the more complicated logic is happening in this, even this isn't that bad. But honestly, I'd love to unit test that, right? And I don't want to mount an entire component to do that.
[00:06:16] So by divorcing the state management from the components, things become easier to test. Usually unit testing is not hard. It's usually we write code that is hard to unit test, right. And it's usually, because that's the big argument for test first, right? So yeah, we're pulling it out and we're being able to use it like that.