javascriptreduxreact-reduxredux-toolkitreselect

understanding selectors memoization with reselect and objects


There is an article on the Redux website about selector memoization with the Reselect library, where they provide next example:

const state = {
  a: {
    first: 5
  },
  b: 10
}

const selectA = state => state.a
const selectB = state => state.b

const selectA1 = createSelector([selectA], a => a.first)

const selectResult = createSelector([selectA1, selectB], (a1, b) => {
  console.log('Output selector running')
  return a1 + b
})

const result = selectResult(state)
// Log: "Output selector running"
console.log(result)
// 15

const secondResult = selectResult(state)
// No log output
console.log(secondResult)
// 15

Overall this example is clear, except for the selectA1 selector. Redux docs stated that

When you call the selector, Reselect will run your input selectors with all of the arguments you gave, and looks at the returned values. If any of the results are === different than before, it will re-run the output selector, and pass in those results as the arguments.

So, if we provide state.a, which is object, as an input selector for selectA1, it will fail === check and run a => a.first every time, right? Or have I misunderstood something?


Solution

  • So, if we provide state.a, which is object, as an input selector for selectA1, it will fail === check and run a => a.first every time, right?

    No, an object reference will always be strictly equal to itself.

    The selectA selector function returns state.a which is a reference to an object with value { first: 5 }. state.a will continue to always be a reference to this object until an action is dispatched to update state.a to then be a reference to a new object with a value, then the selectA1 selector function will recompute its output value.

    I hope this snippet helps illustrate object reference equality.

    const state = {
      a: { first: 5 },
    };
    
    const selectA = state => state.a;
    
    // same reference, true
    console.log(selectA(state) === state.a);
    
    // same "value", but false because different reference
    console.log({ first: 5 } === state.a);