Check out a free preview of the full Advanced Redux with Redux Toolkit course
The "Extra Reducers" Lesson is part of the full, Advanced Redux with Redux Toolkit course featured in this preview video. Here's what you'd learn in this lesson:
Steve uses the extraReducers property to add dependent actions to a slice. This is useful for clean-up tasks such as removing any items associated with a user when the user account is removed.
Transcript from the "Extra Reducers" Lesson
[00:00:00]
>> Let's talk about having interrelated reducers. So like the use case, the problem statement is when I unassign a user or I remove a user, which I probably need to wire up that button at some point, someone remind me. When I remove a user, it should unassign them from whatever tasks are assigned.
[00:00:21]
That seems like reasonable, there's other fun things you can do in this repo if you want to play around afterwards there's select things, we can change all sorts of other fun things. Some of this I will leave in there in case the spirit moved us, or if you want to try some of the stuff out later I've left the setup in there for you.
[00:00:36]
But I think we've got to remove button. We've got both pieces that seems like a fair place to go in and do something. So let's go ahead and kind of look at how we might go about that. Okay, so let's see, the fun part is we got to allude to this before is that I will show you this again just in case, on top of reducers, there is this idea called extraReducers.
[00:01:04]
And the heuristic here is the reducers are the ones that are tightly bound the slice, extraReducers are the other things that the thing might care about, right? So for instance, maybe there's a logout action where you maybe want to just dump everything that's in state and then clean it out, right?
[00:01:24]
So they're not walking around some zombie state where they're logged out, but all the data's still loaded. That's like a use case. There's all sorts of things that might happen that you might want to deal with. ExtraReduces are like, here are the extra or additional things that aren't the done for me prewired up ready to go things.
[00:01:45]
So really if we think about it like The tasks wants to know when a user has been removed, right? It has a concern over there, and I don't wanna fire two actions. I don't wanna fire user slash remove user. And then also tasks slash unassigned user from tasks, right?
[00:02:06]
Because every reducer gets every action no matter what. So you have multiple things that are just amazing because again, you just say that a thing happened in a Redux codebase. You're like, a user has been removed. Everyone gets the message, right? Whoever cares about it can deal with it, and whoever doesn't care about it just lets it fall through the conditions, right?
[00:02:29]
It's actually super elegant and makes sometimes what seems like otherwise complicated things make a ton of sense. So that's where that builder comes back in. There is an object notation again just like you saw above, where you can use the action types and then use that syntax with the square brackets to key them in.
[00:02:48]
That is planned to be deprecated for Redux Tools Kit 2.0, so I'm just not gonna do it. You can look it up but even maybe by the time you watch it, it's gone so we're gonna do the thing that's here to stay. And so, we'll have that in place also because it's a nice pattern.
[00:03:06]
I like it. We've got the builder and this works exactly like the create reducer that I showed you before. That create reducer that we're using, didn't have this idea, it wasn't a slice, it didn't have this idea of these bound actions to it, it simply was there for anything, I made those strings up increment decrement.
[00:03:25]
I made all that up, I mean I didn't make up the word increment and decrement and the idea that would change the number at a counter, but you get what I mean. So this works the same way, and where this becomes really really cool which is builder, the addCase .remove, or not even removed just pass in, like we saw this actually earlier.
[00:03:49]
That's why I kind of seated in to both sell you on the fact that you could use these things piecemeal, and also to kind of lay the groundwork for this. That is the action creator that we call to create the action that we eventually dispatched. But that is all that builder needs to know.
[00:04:09]
I'll set up all the conditions and everything for this, and we'll be good to go. And you ready for this? It's coming. Not if I put the comma there. I'm going to be so happy. All right. Here's one that's not a surprise. Yeah, I didn't read it yet.
[00:04:34]
It's fine. The state. Don't spoil the surprise. The task state is the task state, right? Cool, cool, cool. That action is perfectly typed. It knew everything about it. It grabs the return type as we saw before in the counter example. And so, I don't have to guess and remember and jump back over to that reducer or that action creator and try to guess what the properties on it are.
[00:04:57]
It knows the type of it, it knows what the payload is going to be. Everything is good to go, especially because I think we made a game time decision to just use the IDs. It knows that payload is just a string. And I get all of that wired up, ready to go.
[00:05:13]
And so there we can basically say now the tricky part is, it's you have to remember how to do stuff immutably which is a little bit fun, but let's go ahead and we'll try it out. And this is where you can't outright replace it. So let's see. We got let's grab the user ID, let's just for the action payload.
[00:05:37]
Yeah, I want to call it that so it's less confusing for me. Actually not payload just to name it a little bit better I guess I could have done something fun there but I'm not going to. And then what I'm going to do unless someone's got a better plan, because I'm here for it especially in TypeScript, object at entries loses its type, definitions, it doesn't really know that the key is the key of the object if you said, like object.keys or whatever.
[00:06:08]
So I can't do some stuff, so I'm very happy with four loops now, which is a thing that if you would ask me five years ago, the last time, people change and they grow, okay? So iterate through, that cost task of the state entities. And we're going to say hey, if your test user is equals userId, I guess I could delete it off the object too.
[00:06:44]
I'm so uncomfortable with immutable state. But it's nice. Most of the time I don't have to sit there and spread operator my way up. But it's still slightly disorienting. All right, so go through every task. If previously you were pointing to user 123 and user 123 is the one that we removed, destroy that reference, right?
[00:07:08]
Just set it to undefined and that task is no longer pointed at that user, right? And that's it really. And now if we wire up the remove button, we should see that in place and yeah. So now since every slice, every reducer listens to everything, you just tell them what they care about and you say what you should do to yourself.
[00:07:28]
They only have access to their own state, but they have access to messages and actions from throughout the application. So let's go ahead and we'll just
>> So this is when you delete a user.
>> Yep.
>> Delete all their tasks. How would the scale with a for loop like that?
[00:07:43]
>> I mean, ideally like one. Hopefully, I have a API at some point. This remove user could be the ones that state or I'm getting back a new list of users. I'm blowing it away from the API, or something like that, right? If this is purely just the client side thing, right?
[00:08:06]
Ideally the list hasn't grown that big, right? So yeah, this assumes, one of the things we'll talk about a little bit is I think estate management and data fetching are two problems that are similar both different, right? And so here we're aiming for, this is probably a relatively constrained data set because it all clients data to begin with, right?
[00:08:29]
This could have been like, they were like they had a bunch of search queries and we removed, like the last time I did this is it was a advanced search query builder that wasn't going to get more than five or six rows. But when you hit an X, I needed to remove it from the filtering on the list and remove it from the UI, which were being stored in different places, right?
[00:08:48]
So I simply announced that they removed it. The various two or three places. I think it changed the URL, two of the query programs, right? So I had three different parts of my UI, but it wasn't me processing big data that I had loaded in memory in Permium.
[00:09:01]
>> Right, okay. It was bound and I think, yeah, if you have something that grows to a bigger thing, there are things that you can do. It's tricky because most of them involve asynchrony. So you would have to either right middleware or use a thunk tl dr, when you have to iterate over a whole bunch of stuff in the browser.
[00:09:19]
Setting a, doing 10, set a timeout for the next hit of the event loop and doing another 10, is a great strategy cause it lets clicks and other things get in there, right? So there are ways to do it, but we're gonna assume this is, I had just had some UI and we were building a thing that eventually I was going to have to put together, but it didn't get too big in size.
[00:09:37]
All right. So we've got that in place. Now I do need to go to an individual user and wire up that delete button. So we go ahead and one day doesn't remove user, a day it's gonna remove user today. Today is the day that removes a user. It's nice to leave yourself a little presence when you're live coding.
[00:10:04]
So we pull that in, and then we've got a use AppDispatch. That should be your shortcut editor eventually, awesome. And we can do editing, we can do a whole bunch of stuff. And this will be interesting, because if I do show the user, I'll give you this one is kind of an exercise.
[00:10:25]
I'm just being mindful of time. Where you can say they edit the name in the sidebar. I also want to edit the name on the tasks, right? That's definitely a side quest that one should investigate going on. But here it will just dispatch that action. And I guess I made a different decision last time.
[00:10:47]
We'll do the user ID and we'll dispatch it. Cool, let's verify that everything works before I say it does and push stuff up. So ideally, if we remove Dr. Strange, you can see this now no one is assigned by two things. Just I announced that happen once. Everything that cares.
[00:11:15]
Everyone that cares does what they need to do. And life goes on. And is that easy to test? Yeah. You just have an array in your tasks that have one of them with the right user ID, you've send one of those actions and the action creator and you make sure it's gone, right?
[00:11:33]
And then you leave that test in there forever. Because that runs in a millisecond. And you have confidence. But this does that thing forever and ever and ever. And I've got a bunch of unassigned tasks. Yeah, there are side quests to go on here if you wanna explore more and like just want a playground to play in.
[00:11:52]
There's some selects you can drop in here. There's a bunch of other stuff like that.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops