Hi there! Can I nest one selector inside result function of another selector? Would every instance of nested selector be memoized?
example:
const itemComputedSelector = (key) => createSelector(
// some stuff, return computed data
)
export default createSelector(
state => state,
itemsSelector // return ['A', 'B', 'C'],
(state, items) => (
items.map((itemKey) => itemComputedSelector(itemKey)(state)
// and some stuff with result array, and return this array
)
)
Technically, you can do that, but it will then always recompute on every state change since state is being passed as one parameter to check for cache invalidation.
Instead of creating a selector using key, create a selector that returns another selector that itself accepts key:
const itemKeyReifierSelector = createSelector(
// selectors which select state slices that the computor depends on.
state => state.path.to.dep0,
state => state.path.to.dep1,
selectorThatSelectsDep2,
// and of course, the computor down here.
(dep0, dep1, dep2) =>
// NOTE: This computed function will change any time
// one of the deps changes,
(itemKey) => getItemFromDeps(itemKey, dep0, dep1, dep2)
)
export default createSelector(
itemsSelector,
// No need to pass in `state` directly, itemKeyReifierSelector
// handles binding state slices to a function.
itemKeyReifierSelector,
// NOTE: The $ prefix is what I use to signal a derived function.
// It is not necessary.
(items, $itemKeyReifier) =>
items.map($itemKeyReifier)
)
UPDATE 2019-09-30: Edited itemKeyReifierSelector to make the intention clear.
Technically, you can do that, but it will then always recompute on every state change since
stateis being passed as one parameter to check for cache invalidation.Instead of creating a selector using
key, create a selector that returns another selector that itself acceptskey:const itemKeyReifierSelector = createSelector( // selectors which select state slices that the computor depends on. (dep0, dep1, dep2) => // NOTE: This computed function will change any time // one of the deps changes, (itemKey) => getItemFromDeps(itemKey, dep0, dep1, dep2) ) export default createSelector( itemsSelector, // No need to pass in `state` directly, itemKeyReifierSelector // handles binding state slices to a function. itemKeyReifierSelector, // NOTE: The $ prefix is what I use to signal a derived function. // It is not necessary. (items, $itemKeyReifier) => items.map($itemKeyReifier) )
This pattern doesn't work... when you call itemKeyReifierSelector(itemKey), it'll pass the first argument as the state argument. your state won't be available to the selector unless you actually pass in the state.
The pattern does work, however the sketch that I wrote out was not clear. I have updated the sketch to show the actual intent.
The pattern does work, however the sketch that I wrote out was not clear. I have updated the sketch to show the actual intent.
Oh, I am seeing where I went wrong. I was calling the itemKeyReifierSelector selector in the body of my actual selector, but what you have to do is pass the selector as one of the first args to createSelector, then you'll be returned the memoized selector.
Thanks so much!
Most helpful comment
Technically, you can do that, but it will then always recompute on every state change since
stateis being passed as one parameter to check for cache invalidation.Instead of creating a selector using
key, create a selector that returns another selector that itself acceptskey:UPDATE 2019-09-30: Edited
itemKeyReifierSelectorto make the intention clear.