diff --git a/src/index.js b/src/index.js index 6c1928d3c..afa034a52 100644 --- a/src/index.js +++ b/src/index.js @@ -83,3 +83,17 @@ export function createStructuredSelector(selectors, selectorCreator = createSele } ) } + +const indexResolver = (state, index) => index + +export function createIndexedSelector(selectorFactory, resolver = indexResolver) { + const cache = {} + const indexedSelector = (...args) => { + const key = resolver(...args) + const selector = cache[key] || (cache[key] = selectorFactory()) + return selector(...args) + } + + indexedSelector.at = (key) => cache[key] + return indexedSelector +} diff --git a/test/test_selector.js b/test/test_selector.js index e01c19bdd..2cddfb677 100644 --- a/test/test_selector.js +++ b/test/test_selector.js @@ -1,7 +1,7 @@ // TODO: Add test for React Redux connect function import chai from 'chai' -import { createSelector, createSelectorCreator, defaultMemoize, createStructuredSelector } from '../src/index' +import { createSelector, createSelectorCreator, defaultMemoize, createStructuredSelector, createIndexedSelector } from '../src/index' import { default as lodashMemoize } from 'lodash.memoize' const assert = chai.assert @@ -342,4 +342,20 @@ suite('selector', () => { ) assert.equal(selector.resultFunc, lastFunction) }) + test('indexed selector', () => { + const selector = createIndexedSelector(() => + createSelector( + (state, index) => state.a[index], + (state, index) => state.b[index], + (a, b) => a + b + ) + ) + assert.equal(selector({ a: [ 0, 1 ], b: [ 0, 1 ] }, 0), 0) + assert.equal(selector.at(0).recomputations(), 1) + assert.equal(selector({ a: [ 'a', 1 ], b: [ 0, 1 ] }, 0), 'a0') + assert.equal(selector.at(0).recomputations(), 2) + assert.equal(selector({ a: [ 0, 1 ], b: [ 0, 1 ] }, 1), 2) + assert.equal(selector.at(0).recomputations(), 2) + assert.equal(selector.at(1).recomputations(), 1) + }) })