Search code examples
reactjsredux-toolkitreselect

Does reselect memoize in case we return empty array or object as fallback


Assume we have a selector written with createSelector

const getSmth = createSelector(
  getState,
  state => state.items || {}
)

Does memoization still works or it will recalculate each time cause we return a new reference? As far as I know, reselect does equality check by reference ===? Or reselect store this to a variable and the reference will be the same?


Solution

  • getSmth is a generated selector. getState is the input selector, state => state.items || {} is the output selector

    If the generated selector is called multiple times, the "output" selector will only be recalculated when the extracted values have changed.

    The calculated result(derived data) has nothing to do with the recalculation. This means the output selector returns the same reference or a new reference does not matter.

    createSelector determines if the value returned by an input-selector has changed between calls using reference equality (===).

    E.g.

    import { createSelector } from 'reselect';
    
    const state = { items: undefined };
    const getState = (state) => state;
    
    const getSmth = createSelector(getState, (state) => {
      console.log('[getSmth] resultFunc');
      return state.items || {};
    });
    
    getSmth(state);
    getSmth(state);
    console.assert(
      getSmth.recomputations() === 1,
      'should calculate once if the reference passed into the selector is the same',
    );
    
    const getSmth1 = createSelector(getState, (state) => {
      console.log('[getSmth1] resultFunc');
      return state.items || {};
    });
    
    const shallowCopy = (state) => ({ ...state });
    
    getSmth1(shallowCopy(state));  // memorize input for first call
    getSmth1(shallowCopy(state));  // compare input of second call with the input of first call using `defaultEqualityCheck`(`===`)
    console.assert(getSmth1.recomputations() === 2, 'should caculate twice if a new reference passed into the selector');
    

    Output:

    [getSmth] resultFunc
    [getSmth1] resultFunc
    [getSmth1] resultFunc