Allow selector dependencies to be selector factories
As noted in the docs, if you are not careful, memoization can be undone when using a selector with props in multiple components.
The solution is to use a selector factory and pass that to mapStateToProps instead. This works well for one level deep selectors, however, if we are composing memoized selectors the same caveats apply. It is very easy to unintentionally undo the memoization as we nest. The solution again is to keep wrapping our sub-selectors in factories and executing them as we create the selectors.
A neater approach is to always accept either a selector or a selector factory in the createSelector function and handle it in a similar manner as react-redux connect does. This would allow us nest selector factories without having to explicitly execute the factory.
This change means the way selectors are used is identical whether they are
- Pure Functions
- Memoized Singletons
- Reusable Memoized Factories
- Composed from the above types
- Used directly in mapStateToProps
For example:
// moduleA.js
export somePureSelector = (state, props) => state.a + props.b;
// moduleB.js
export someMemoizedSelector = () => createSelector(
(state) => state.a,
(state, props) => props.b,
(a, b) => a + b
);
// moduleC.js
export composedSelector = () => createStructuredSelector({
a: somePureSelector,
b: someMemoizedSelector
});
// ContainerA.js
export connect(somePureSelector)(SomeComponent);
// ContainerB.js
export connect(someMemoizedSelector)(SomeComponent);
// ContainerC.js
export connect(composedSelector)(SomeComponent);
I realize this PR is incomplete, I just wanted to get people's opinion on the change.
Coverage remained the same at 100.0% when pulling 7c2719a593f9068e43610ac0024ff072f58e0065 on madcapnmckay:selectorFactories into 7cab533a2045089623f925bbb158ffc80f6127be on reactjs:master.
Codecov Report
Merging #321 into master will not change coverage. The diff coverage is
100%.
@@ Coverage Diff @@
## master #321 +/- ##
=====================================
Coverage 100% 100%
=====================================
Files 1 1
Lines 15 16 +1
=====================================
+ Hits 15 16 +1
| Impacted Files | Coverage Δ | |
|---|---|---|
| src/index.js | 100% <100%> (ø) |
:arrow_up: |
Continue to review full report at Codecov.
Legend - Click here to learn more
Δ = absolute <relative> (impact),ø = not affected,? = missing dataPowered by Codecov. Last update 7cab533...7c2719a. Read the comment docs.
Hi @madcapnmckay, just to point out that re-reselect, let you declare selectors which internally behave like a factory but keep the same API of a normal reselect selector outside.
This allows forgetting differences between selectors and selector factories.
@toomuchdesign while true, that's somewhat different to the proposed solution.
This PR is obviously stale, especially compared to what's in master atm.
Looking at it, I think I sorta get what's going on, and if you or someone is interested in reviving this vs the latest master we can at least take a look and discuss.