Reselect: Question: Can I nest one selector inside result function of another selector?

Created on 26 Jul 2018  路  4Comments  路  Source: reduxjs/reselect

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
   )
)

Most helpful comment

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.

All 4 comments

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 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.
  (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!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

0x80 picture 0x80  路  5Comments

jEnbuska picture jEnbuska  路  6Comments

sarink picture sarink  路  4Comments

maxim1006 picture maxim1006  路  3Comments

vjau picture vjau  路  5Comments