简体   繁体   English

'createSelector'如何在'reselect'库中接受输入参数?

[英]How 'createSelector' is accepting input parameter in 'reselect' library?

I have taken the following code from the reselect library. 我从重新选择库中获取了以下代码。

When subtotalSelector is invoked with exampleState , it will invoke the function createSelector that accepts the input parameter exampleState . 当使用exampleState调用subtotalSelector ,它将调用接受输入参数exampleState的函数createSelector

My question is about how createSelector is accepting exampleState and the other functions consuming it? 我的问题是关于createSelector如何接受exampleState和其他使用它的函数? There is some implicit injection of the parameter happening which I don't understand. 我不理解该参数的隐式注入。

import { createSelector } from 'reselect'

const shopItemsSelector = state => state.shop.items
const taxPercentSelector = state => state.shop.taxPercent

const subtotalSelector = createSelector(
  shopItemsSelector,
  items => items.reduce((acc, item) => acc + item.value, 0)
)

const taxSelector = createSelector(
  subtotalSelector,
  taxPercentSelector,
  (subtotal, taxPercent) => subtotal * (taxPercent / 100)
)

export const totalSelector = createSelector(
  subtotalSelector,
  taxSelector,
  (subtotal, tax) => ({ total: subtotal + tax })
)

let exampleState = {
  shop: {
    taxPercent: 8,
    items: [
      { name: 'apple', value: 1.20 },
      { name: 'orange', value: 0.95 },
    ]
  }
}

console.log(subtotalSelector(exampleState)) // 2.15

The subtotalSelector is little more explainable by replacing the input parameters. 通过替换输入参数, subtotalSelector解释更多。

subtotalSelector = createSelector(
  state => state.shop.items,
  items => items.reduce((acc, item) => acc + item.value, 0)
)

subtotalSelector({
  shop: {
    taxPercent: 8,
    items: [
      { name: 'apple', value: 1.20 },
      { name: 'orange', value: 0.95 },
    ]
  }
});

I did not find a better way to dissect this reselect library code , but to add console.log inside the functions. 我没有找到更好的方法来剖析此重新选择的库代码 ,而是在函数内部添加console.log The following code is copied from the reselect library itself. 以下代码是从reselect库本身复制的。 The JSBin version can be found here . 您可以在此处找到JSBin版本。

At the bottom of the console output, you can see that the exampleState is really the arguments variable used in the code. 在控制台输出的底部,您可以看到exampleState实际上是代码中使用的arguments变量。 It is a JavaScript construct . 这是一个JavaScript 构造

 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 } function defaultMemoize(func, equalityCheck = defaultEqualityCheck) { let lastArgs = null let lastResult = null console.log("Entering defaultMemoize"); console.log("###INPUT### defaultMemoize argument func type: " + typeof func); // 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 } function createSelectorCreator(memoize, ...memoizeOptions) { console.log("Entering createSelectorCreator"); console.log("#INPUT# argument memoize name: " + memoize.name); console.log("#INPUT# argument memoize options: "); console.log(memoizeOptions); return (...funcs) => { let recomputations = 0 const resultFunc = funcs.pop() const dependencies = getDependencies(funcs) console.log("##INPUT## argument funcs: "); console.log(resultFunc); const memoizedResultFunc = memoize( function () { recomputations++ // apply arguments instead of spreading for performance. return resultFunc.apply(null, arguments) }, ...memoizeOptions ) console.log("memoizedResultFunc: " + typeof memoizedResultFunc); // 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 if (arguments != null) { console.log("***INPUT*** arguments: "); console.log(arguments); } 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 } } const createSelector = createSelectorCreator(defaultMemoize) 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 }, {}) } ) } const shopItemsSelector = state => state.shop.items const taxPercentSelector = state => state.shop.taxPercent const subtotalSelector = createSelector( shopItemsSelector, items => items.reduce((acc, item) => acc + item.value, 0) ) const taxSelector = createSelector( subtotalSelector, taxPercentSelector, (subtotal, taxPercent) => subtotal * (taxPercent / 100) ) const totalSelector = createSelector( subtotalSelector, taxSelector, (subtotal, tax) => ({ total: subtotal + tax }) ) let exampleState = { shop: { taxPercent: 8, items: [ { name: 'apple', value: 1.20 }, { name: 'orange', value: 0.95 }, ] } } console.log(subtotalSelector(exampleState))// 2.15 //console.log(taxSelector(exampleState))// 0.172 //console.log(totalSelector(exampleState))// { total: 2.322 } 

The following code shows an example of functional composition similar to the above. 以下代码显示了与上述类似的功能组成示例。

 function firstFunction() { console.log(arguments); } function secondFunction() { console.log(arguments); } function thirdFunction() { console.log(arguments); } function fourthFunction() { console.log(arguments); return function() { return function(x) { console.log(arguments); }; } } const higherOrderFunction = fourthFunction(thirdFunction); console.log("High Order Function"); console.log(higherOrderFunction); const highestOrderFunction = higherOrderFunction(firstFunction, secondFunction); console.log("Highest Order Function"); console.log(highestOrderFunction); highestOrderFunction(10); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM