I'm learning the usage of reselect, but i'm confused about the way i make use of the memoized selector in inside my container.
I've got a component called Summary that received 3 props thats are subtotal, tipAmount , total .
It looks like this export const Summary = ({ subtotal = 0, tipAmount = 0, total = 0 })=>{...}.And those props are being inject my the connect HOC inside a dedicated container that i've called SummaryContainer with the following code.
import { connect } from 'react-redux';
import { Summary } from '../components/Summary';
import {
selectTipAmount,
selectSubtotal,
selectTotal
} from '../store/items/selectors';
const mapStateToProps = (state) => {
const subtotal = selectSubtotal(state);
const tipAmount = selectTipAmount(state);
const total = selectTotal(state);
return {
subtotal,
tipAmount,
total
};
};
export const SummaryContainer = connect(mapStateToProps)(Summary);
As you can see this code uses 3 selectors selectTipAmount , selectSubtotal and selectTotal that i'm importing from a selector file with the follwing code.
import { createSelector } from 'reselect';
const selectItems = (state) => state.items;
const selectTipPercentage = (state) => state.tipPercentage;
export const selectSubtotal = createSelector([selectItems], (items) =>
items.reduce((acc, { price, quantity }) => acc + price * quantity, 0)
);
export const selectTipAmount = createSelector(
[selectSubtotal, selectTipPercentage],
(subtotal, tipPercentage) => subtotal * (tipPercentage / 100)
);
export const selectTotal = createSelector(
[selectSubtotal, selectTipAmount],
(subtotal, tipAmount) => subtotal + tipAmount
);
export const selectItemWithTotal = createSelector([selectItems], (items) =>
items.map((item) => ({ ...item, total: item.price * item.quantity }))
);
export const selectItem = (state, props) =>
state.items.find((item) => item.uuid === props.uuid);
export const selectItemTotal = createSelector(
[selectItem],
(item) => item.price * item.quantity
);
So here is my problem :
When i call write const total = selectTotal(state);inside mapStateToProps i passe to the total constant the results of the execution of selectTotal(state) selector and when i look at the argument, it's state.It looks like i'm invoking the selectTotal selector by passing and state argument, but in the actuel implementation it isn't a function that takes a state param.In the actual implementation that selection equals the result of createSelect function like this:
export const selectTotal = createSelector(
[selectSubtotal, selectTipAmount],
(subtotal, tipAmount) => subtotal + tipAmount
);
I haven't seen where the state argument is being passed.What is going on?
The code works perfectly but i'm lost about where the state argument is being used.
When i look at selectItems selector it makes sens, but with selectors that are created with createSelector i'm lost.
I find it easiest to think of
reselectselectors as sort of the "opposite" of redux reducer functions. With reducer functions each reducer owns a chunk of state and when they are combined they form a reducer tree where once they are all combined form the entirestateobject.The selectors are basically doing the opposite. They start with simple selectors that take the entire
stateobject and pluck out chunks of it. These sub-state chunks can then be fed into created selectors to pluck out smaller chunks (or compute derived state). The inputs used increateSelectorare a sort of "dependency", when one of them updates then the selector recomputes its value.createSelectoris essentially a higher order function that consumes "dependencies" and a result function, and returns a function that consumes thestateobject. When you callselectSubtotaland passstateyou are really passingstateto a selector tree (or set of trees).For example, when
state.itemsupdates theselectItemsselector that is an input toselectSubtotalwill update its return value. This update will triggerselectSubtotalto then recompute its value, and so on for any other selectors that useselectSubtotalas an input.If you are curious, the resultant selector function will also have a
resultFuncproperty that matches the computing function originally passed tocreateSelector. For example,selectTipAmount.resultFuncwill be(subtotal, tipPercentage) => subtotal * (tipPercentage / 100), called likeselectTipAmount.result.Func(subTotal, tipPercentage);. I use this heavily when unit testing my selectors since I really don't care about memoizing a value, but rather that they correctly compute derived state; I won't need to mock up an entire state object that matches the selector dependencies.