Check out a free preview of the full Redux Fundamentals (feat. React) course
The "Computing Data with Reselect" Lesson is part of the full, Redux Fundamentals (feat. React) course featured in this preview video. Here's what you'd learn in this lesson:
Steve demonstrates creating selectors to pull specific data from a large store tree and allow for more code flexibility if the shape of the state tree changes. The createSelector method takes two arguments an array of functions and a function to pass the array through.
Transcript from the "Computing Data with Reselect" Lesson
[00:00:00]
>> All right, to the selector part of the show. Let's go into our store in this case, and let's just make a selectors file. We'll call it selectors.js. Cool, and reselect, basically the main one we're gonna use is one called createSelector. Again, you saw useSelector before when we used the hooks, this is a very similar idea.
[00:00:31]
A selector is basically something that takes your large state tree and gets the parts that you need out of it. So if you think about from the counter example we saw with the hooks, we might have had something like export const selectItems, which is just gonna be state.
[00:00:54]
Equal sign here, state, items. We saw that before with the counter before. Same thing for tip percentage, we could say selectTipPercentage. And I'm prefixing them all with select, that is more of a convention. Again, you could call them whatever you want, cuz it's just JavaScript. selectTipPercentage is state.TipPercentage, right?
[00:01:22]
So these are just functions, they're gonna pull each of those parts of the state tree off of our Redux state. There's nothing special about them. createSelector takes two major arguments, an array of functions, right? Very similar to the array that we would use in use memory, use callback.
[00:01:41]
And then a function to pass all the results of those through to compute your new value. The trick is, it will look at, for instance, we pass in selectItems, selectTipPercentage. If the return values of these functions are unchanged, it'll just give you back the same value it gave last time and skip the expensive computation.
[00:02:03]
This is a cheap computation in our case, but if this was a more expensive computation, it becomes a lot cheaper, cuz we're not running it over and over and over again. The other thing is, I would really, really, really push you to use selectors, even there as simple as this one, all over the place.
[00:02:22]
Let's say, hypothetically, you used state.Items throughout your code base, right? Code base grows, you move that somewhere else in the state tree, or you refactor the state tree in some way. You gotta find all those state.Items and change them. Versus if you made a function called selectItems, and it did that, use that function everywhere.
[00:02:45]
And then all of a sudden you change the shape of your state tree. You just gotta update that function, and the rest of your code base will be resilient and move along and get the hint. And then you don't have to change things over and over in your code base, right?
[00:02:58]
I think a lot of the ways that front end code bases break down on an architectural level, is they become so much complication and so many tedium things to change and things keep breaking, that you can't ship any new features. But giving yourself good abstractions, sometimes even before you think you need them, you give yourself the ability to make changes and change your mind later.
[00:03:17]
I always try to optimize for, can I change my mind later? So let's start by creating ability to get a subtotal. And we'll kind of get a sense for how this syntax works. So, subtotal is totally just based on the items. So let's go ahead and we'll do that.
[00:03:37]
We'll say export const subtotal, so I selectSubtotal. And that's gonna be very similar to what we saw before, we're gonna start out with this createSelector. And really the only things that the selectSubtotal needs is go ahead and select all the items. So this will run the selectItems function, which will get us the items.
[00:04:02]
If that array is the exact same array as the last time it was called, right? Even in multiple map dispatch to props, like right now we have one map dispatch to props, it's using that. But let's say you're using a very similar thing throughout the code base. It will run it once, until that changes, it will just return the same value.
[00:04:20]
So as long as everything in this array is the same. But we'll take the return result, which is going to be that array of items and we'll pass it through. This is gonna be very similar to what we had before, which is items.reduce. I was gonna take the sum and the item, I could have just copy and paste this probably as well.
[00:04:39]
Sum of the item, and we'll say sum + item.price * item quantity, start from 0, right? And so now this is very similar to what we had before well. Anytime we need to compute a subtotal, this will work. And we'll only do this math once until the array changes again.
[00:05:01]
Cool, let's go ahead and let's try the other two as well, just to kinda get some muscle memory. So selectTipAmount involves two things. It needs the subtotal, right, which we already have a selector for. And then it needs the selectTipPercentage, which we already have a selector for. So you can start to build these on top of each other, right?
[00:05:24]
As each one can stand on the shoulders of the previous one. And again, if this hasn't changed, and this hasn't changed, then we'll cache the result of this next selector as well. So we'll say export const and we'll say selectTipAmount. Now will again be create selector and again, what are the two things this cares about?
[00:05:48]
Well, it cares about the results of selectSubtotal and it cares about the results of selectTipAmount. And with that, oops, not selectTipAmount, selectSubtotal and selectTipPercentage. Right, and with that the two results will be the subtotal from the first argument in the array. And the second argument in the array will be the tip percentage.
[00:06:15]
And then we can simply add those two things together. Right, and then finally the last one that we had was export const total, or now it's gonna be selectTotal, will be create selector. So this one now needs to know about the subtotal and the tip amount. So this is again standing on previous selectors that we wrote.
[00:06:45]
Looking at this one and this one, these have the same results. This will always return the same result as well. So we'll selectSubtotal and we'll selectTipAmount. And that's just adding them. So this will give us our subtotal, subtotal + tipAmount. Great, so now we have these in place, we can swap these out in our map state to props really easily.
[00:07:19]
So let's go ahead and try that out. And now instead of doing all this logic here, we can get rid of all of this. And we're gonna say const subtotal = selectSubtotal based on the state. Const tipAmount, = selectTipAmount based on the state. Const total = selectTotal based on the state.
[00:07:57]
>> You've made a typo in calculations in selectors.
>> All right, where is it?
>> It seems like we need to multiply subtotal and tip percentage.
>> Yep, perfect, thank you. Not good at math. I used to be a seventh grade teacher. So, you think. All right, cool.
[00:08:19]
We can see that everything still works as expected. We'll go modify this a little bit. We see we're recalculating these values.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops