re-reselect
Version:
Enhance Reselect selectors with deeper memoization and cache management
100 lines (77 loc) • 3.06 kB
JavaScript
import {createSelector} from 'reselect';
import FlatObjectCache from './cache/FlatObjectCache';
const defaultCacheCreator = FlatObjectCache;
const defaultCacheKeyValidator = () => true;
function createCachedSelector(...funcs) {
return (polymorphicOptions, legacyOptions) => {
// @NOTE Versions 0.x/1.x accepted "options" as a function
if (typeof legacyOptions === 'function') {
throw new Error(
'[re-reselect] Second argument "options" must be an object. Please use "options.selectorCreator" to provide a custom selectorCreator.'
);
}
const options = {};
if (typeof polymorphicOptions === 'function') {
Object.assign(options, legacyOptions, {keySelector: polymorphicOptions});
// @TODO add legacyOptions deprecation notice in next major release
} else {
Object.assign(options, polymorphicOptions);
}
// https://github.com/reduxjs/reselect/blob/v4.0.0/src/index.js#L54
let recomputations = 0;
const resultFunc = funcs.pop();
const dependencies = Array.isArray(funcs[0]) ? funcs[0] : [...funcs];
const resultFuncWithRecomputations = (...args) => {
recomputations++;
return resultFunc(...args);
};
funcs.push(resultFuncWithRecomputations);
const cache = options.cacheObject || new defaultCacheCreator();
const selectorCreator = options.selectorCreator || createSelector;
const isValidCacheKey = cache.isValidCacheKey || defaultCacheKeyValidator;
if (options.keySelectorCreator) {
options.keySelector = options.keySelectorCreator({
keySelector: options.keySelector,
inputSelectors: dependencies,
resultFunc,
});
}
// Application receives this function
const selector = function(...args) {
const cacheKey = options.keySelector(...args);
if (isValidCacheKey(cacheKey)) {
let cacheResponse = cache.get(cacheKey);
if (cacheResponse === undefined) {
cacheResponse = selectorCreator(...funcs);
cache.set(cacheKey, cacheResponse);
}
return cacheResponse(...args);
}
console.warn(
`[re-reselect] Invalid cache key "${cacheKey}" has been returned by keySelector function.`
);
return undefined;
};
// Further selector methods
selector.getMatchingSelector = (...args) => {
const cacheKey = options.keySelector(...args);
// @NOTE It might update cache hit count in LRU-like caches
return cache.get(cacheKey);
};
selector.removeMatchingSelector = (...args) => {
const cacheKey = options.keySelector(...args);
cache.remove(cacheKey);
};
selector.clearCache = () => {
cache.clear();
};
selector.resultFunc = resultFunc;
selector.dependencies = dependencies;
selector.cache = cache;
selector.recomputations = () => recomputations;
selector.resetRecomputations = () => (recomputations = 0);
selector.keySelector = options.keySelector;
return selector;
};
}
export default createCachedSelector;