reselect icon indicating copy to clipboard operation
reselect copied to clipboard

Allow selector dependencies to be selector factories

Open madcapnmckay opened this issue 7 years ago • 5 comments

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.

madcapnmckay avatar Feb 09 '18 23:02 madcapnmckay

Coverage Status

Coverage remained the same at 100.0% when pulling 7c2719a593f9068e43610ac0024ff072f58e0065 on madcapnmckay:selectorFactories into 7cab533a2045089623f925bbb158ffc80f6127be on reactjs:master.

coveralls avatar Feb 09 '18 23:02 coveralls

Codecov Report

Merging #321 into master will not change coverage. The diff coverage is 100%.

Impacted file tree graph

@@          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 data Powered by Codecov. Last update 7cab533...7c2719a. Read the comment docs.

codecov-io avatar Feb 10 '18 04:02 codecov-io

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 avatar Feb 18 '18 01:02 toomuchdesign

@toomuchdesign while true, that's somewhat different to the proposed solution.

abritinthebay avatar Sep 28 '18 18:09 abritinthebay

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.

markerikson avatar Oct 20 '21 01:10 markerikson