| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- function defaultEqualityCheck(a, b) {
- return a === b
- }
- function areArgumentsShallowlyEqual(equalityCheck, prev, next) {
- if (prev === null || next === null || prev.length !== next.length) {
- return false
- }
- // Do this in a for loop (and not a `forEach` or an `every`) so we can determine equality as fast as possible.
- const length = prev.length
- for (let i = 0; i < length; i++) {
- if (!equalityCheck(prev[i], next[i])) {
- return false
- }
- }
- return true
- }
- export function defaultMemoize(func, equalityCheck = defaultEqualityCheck) {
- let lastArgs = null
- let lastResult = null
- // we reference arguments instead of spreading them for performance reasons
- return function () {
- if (!areArgumentsShallowlyEqual(equalityCheck, lastArgs, arguments)) {
- // apply arguments instead of spreading for performance.
- lastResult = func.apply(null, arguments)
- }
- lastArgs = arguments
- return lastResult
- }
- }
- function getDependencies(funcs) {
- const dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs
- if (!dependencies.every(dep => typeof dep === 'function')) {
- const dependencyTypes = dependencies.map(
- dep => typeof dep
- ).join(', ')
- throw new Error(
- 'Selector creators expect all input-selectors to be functions, ' +
- `instead received the following types: [${dependencyTypes}]`
- )
- }
- return dependencies
- }
- export function createSelectorCreator(memoize, ...memoizeOptions) {
- return (...funcs) => {
- let recomputations = 0
- const resultFunc = funcs.pop()
- const dependencies = getDependencies(funcs)
- const memoizedResultFunc = memoize(
- function () {
- recomputations++
- // apply arguments instead of spreading for performance.
- return resultFunc.apply(null, arguments)
- },
- ...memoizeOptions
- )
- // If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
- const selector = defaultMemoize(function () {
- const params = []
- const length = dependencies.length
- for (let i = 0; i < length; i++) {
- // apply arguments instead of spreading and mutate a local list of params for performance.
- params.push(dependencies[i].apply(null, arguments))
- }
- // apply arguments instead of spreading for performance.
- return memoizedResultFunc.apply(null, params)
- })
- selector.resultFunc = resultFunc
- selector.recomputations = () => recomputations
- selector.resetRecomputations = () => recomputations = 0
- return selector
- }
- }
- export const createSelector = createSelectorCreator(defaultMemoize)
- export function createStructuredSelector(selectors, selectorCreator = createSelector) {
- if (typeof selectors !== 'object') {
- throw new Error(
- 'createStructuredSelector expects first argument to be an object ' +
- `where each property is a selector, instead received a ${typeof selectors}`
- )
- }
- const objectKeys = Object.keys(selectors)
- return selectorCreator(
- objectKeys.map(key => selectors[key]),
- (...values) => {
- return values.reduce((composition, value, index) => {
- composition[objectKeys[index]] = value
- return composition
- }, {})
- }
- )
- }
|