Reactive Angular with NgRx Creating Reducers
Transcript from the "Creating Reducers" Lesson
>> Lukas Ruebbelke: All right, so we built out a very basic reducer that doesn't do a whole lot. So let's take some time and build this out. And extend that functionality so that instead of just returning state, we can see how it can manipulate state using a mutable operations to update the application state and then communicate that back to your components, or services into your application.
[00:00:40] So you'll notice here that one of the parameters is action. So an action consist of, well, the interface for it is one property. And action will always, always have a type. And more often than not, it will also have a payload. But there are times where you'll have a certain action that it doesn't need any additional information, so for instance like load projects.
[00:01:11] Well, it's just a command link, it's a trigger for an event. But within the action type here, you have a switch statement that looks at that and then it will perform some type of operation. Now what I want to advise everybody from doing, and this is certainly, I think, tempting as I see this quite often, is that, let's say you have a state of create.
[00:01:45] And then within this, performing,
>> Lukas Ruebbelke: Some kind of logic and then nesting it. And so, I have seen reducers, and I may be even, when I first started, I would write reducers like this where you would have a case and then I would have this nested logic in here.
[00:02:12] Don't do that. Trust me, it's gonna be painful. Is that in your reducer, what you want to do is capture the action type, the case and then delegate to a stand alone function.
>> Lukas Ruebbelke: Why would you do this? Because it is testable. So when something is nested, nested logic is, I think, in my mind, one of the three core, if you have an access of evil for testing, nested logic is in there.
[00:02:52] Maybe two. Hidden states is the first one. But nested logic I'd say is probably the second. And stick around to the end, I'll tell you the third one. All right, so we want to create something. So what we're going to do is we're going to return a new state object.
[00:03:15] So with every case, you're going to perform semilunar logic and then return new state. So the selectedProjectId, we're not gonna do anything with that.
>> Lukas Ruebbelke: Selected, I think VS Code is trolling me again. But on the other hand, projects, we do wanna do something with this. And so you'll notice up here, I've created this method, createProject, and so I'm just gonna hook this up real quick.
>> Lukas Ruebbelke: We'll go state.projects, so it's going to take essentially all the projects. And then we're also going to pass in the project we want to create, all right.
>> Lukas Ruebbelke: And so let me, just because this is kind of a cut, copy, and paste operation, I'll do update and delete as well.
>> Lukas Ruebbelke: Update and delete. updateProject and,
>> Lukas Ruebbelke: deleteProject, okay. So for creating, updating and deleting,
>> Lukas Ruebbelke: We're taking in to account those three possible action types. Now, let's go up here and look at these methods real quick.
>> Lukas Ruebbelke: Every operation that you do in your reducer needs to be immutable.
[00:05:14] Now, at first, that was a little like, that sounds hard. You're using a four syllable word. How do I do that? And so one, so I'm just gonna walk through this is a mutable operation primer if you will. It's very, very common, or at least I have done this many, many times of going something like projects.push, push or put a project into an array.
[00:05:52] So I wanna add something to an array.push.
>> Lukas Ruebbelke: Incredibly common. The problem is you're mutating that array. So if you wanted to get that back out, how would you do that?
[00:06:21] Is it say concat returns a new, so anytime you're looking at documentation, it returns a new, it's a pretty good indication that this is an immutable operation you're working with. So what we're doing is we're saying take this array and this value and basically put them together and return a new array.
[00:06:43] What you can also do is a shorthand version of this saying here's a new array. I want to spread the existing projects array into that and then I want to add in project. And so if you look here, this is exactly what is happening.
>> Lukas Ruebbelke: So when you need to update something in a collection, and typically I'd run through and I would usually slice it out or basically chop it out and put the new thing in.
[00:07:17] Or usually I would go through the array and I'd find the thing I wanted to update and then just start fiddling with it, which is even worse. Well, using projects.map again returns a new array after performing this function on every element in that array, is I'm loofing over projects.
[00:07:38] And I'm looking for the project that matches my criteria and then using object.assign, which creates a new object, I'm saying go find the object I want to update. Create a brand new object and basically clone this on to it and then put that in the array instead. So we're now combining two immutable operations to update a collection.
[00:08:03] Finally, delete project, if you want to delete something out of an array this is even easier, just projects.filter. So again, returns a new array minus everything that fails this condition here. So depending on what I may be doing is, it would be unreasonable for me to have to do some kind of immutable operation or collection manipulation here.
[00:08:32] Once we introduced entity, this is actually gonna come a lot simpler where they are doing that under the hood. But for now, I've created these so that you could look and see here is kind of the three most common immutable operations. And so what we're simply doing now is saying, I wanna create a project which returns a new projects array, that project at the end.
[00:08:54] This one is a new projects array that has a new project where the one is that we wanted to update. And this one has a new array minus the one that we wanted to leave. So immutable primer, that was a bonus subject. And then from here let's do one more.
[00:09:13] And we're going to do case, and this will be select. And we're going to return, again, a new object. But in this case, we do want to update the selectedProjectId, so that's going to be action.payload. And projects are going to stay exactly the same.
>> Speaker 2: So what you just showed, that kind of sounds like peer pipes and Angular.
>> Lukas Ruebbelke: Yep.
>> Speaker 2: We have to create a new array.
>> Lukas Ruebbelke: Yep, and so the comment was, is that what I describing is something you would use in like a peer pipe. So we're talking about this in the context of ngrx and Redux but, I use these operations all the time in conservable pipes, or observable streams.
[00:10:08] So if I have an observable operation where I'm stacking things, I use them all the time, filter, map. And so generally, it's kind of to the point now if I'm mutating state, there are times where I will do it at a component level cuz it's like at that point it's presentation state.
[00:10:27] But for application state if I start to be like, this is a mutable operation, stop. And what's interesting is that there's a package that is store freeze, whatever, you can actually freeze your application store. And so it's not recommended you do this in production. But you can freeze it while you're developing, so if you ever, am I mutating something, yes or no?
[00:10:54] And I think possibly, maybe Jafar Hussein did that, or I know he was talking about he recreated a version of that.
>> Lukas Ruebbelke: Yes?
>> Speaker 2: This may be a little bit of a tangent, but one thing that using type script sort of brings out here in these producers is that the payload is something you don't really know anything about.
[00:11:20] So in the select case it's just an integer or a string, actually, I guess for the ID. And then in the create case, the payload is actually a project object. Is there any-
>> Lukas Ruebbelke: You're getting ahead of me there a little bit.
>> Speaker 2: Am I? Okay, good, I'm glad.
>> Lukas Ruebbelke: So let me just do it like an asterisk here. So we're doing this incrementally and we're making some concessions. And so, we'll be starting very slow. For instance, this, actually using actions, types, it just strings, not good. And so this is a very loosely typed, kind of a loosey goosey, like we're gonna build into this so.
[00:11:59] I think even, yeah, the next thing I get into is like, okay, we're dispatching actions is generic objects and don't do that, we have typed scripts. So you're absolutely right. So we are going to start out, and you're going to see some things that is like this is not how we would do it in production, but for the sake of a narrative that we're introducing these in step.