reselect: Does not memoize correctly when filtering by ownProps
Hello,
I found a situation in witch reselect does not memoize correctly when filtering by ownProps.
The scenario is as following: We want a component that computes total amount based on year.
-
State:
[{Year : 2018, Amount: 21}, {Year : 2018, Amount: 21}, {Year : 2017, Amount: 42},]
-
A selector that an accepts year from ownProps and computes the total amount for that year
function getStateList(state) {
return state;
}
const getFilteredState = (state, props) => getStateList(state).filter(s => s.Year === props.year);
function makeGetTotalAmount() {
return createSelector(
[getFilteredState],
(list) => {
return list.reduce((acc, curr) => {
return acc + curr.Amount;
}, 0)
}
);
}
export default makeGetTotalAmount;
- Two instances of a TotalAmount.js component, each accepting the year as props
<TotalAmount year={2018} />
<TotalAmount year={2017} />
- And a makeMapStateToProps in TotalAmount.js component
const makeMapStateToProps = () => {
const getTotalAmount = selectors.makeGetTotalAmount();
const mapStateToProps = (state, props) => {
return {
totalAmount: getTotalAmount (state, props),
}
};
return mapStateToProps;
}
My state is normalized and this seems like a common issue, in my projects at least. I think the problem is that filter creates a new array instance every time, but there is no apparent workaround and the documentation is not clear on what to do in these kind of scenarios.
Thank you very much for the time and effort!
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 15 (5 by maintainers)
Yes, the problem is that your
getFilteredState()
selector is returning a new array instance every time, so Reselect will always run the “output selector” you provided.The answer is to use Reselect to create
getFilteredState
as well. You may also need to change it so that instead of directly usingprops.year
, it acceptsyear
as a separate argument, roughly like this: