2017-04-14 10 views
0

私はreselectライブラリから次のコードを取得しました。'createSelector'は 'reselect'ライブラリの入力パラメータを受け入れていますか?

subtotalSelectorexampleStateで呼び出されると、入力パラメータexampleStateを受け入れる関数createSelectorが呼び出されます。

createSelectorは、exampleStateとそれを消費する他の機能を受け入れる方法についての質問はありますか?私が理解していないパラメータの発生が暗黙的に注入されています。

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 

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 }, 
    ] 
    } 
}); 

答えて

0

私はこのreselect library codeを分析するためのより良い方法を見つけることができませんでしたが、関数の内部console.logを追加します。次のコードは、reselectライブラリ自体からコピーされています。 JSBinのバージョンはhereです。

コンソール出力の最後に、exampleStateがコードで実際に使用されているargumentsであることがわかります。 JavaScript constructです。

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 }

次のコードは、上記と同様の機能構成の一例を示しています。

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);

関連する問題