Reselect主要为Redux的state数据提供了Memoize功能。它能够计算数据,传递最少且必要的state值;具有高性能,只在传递值改变时才会重新计算;具有可组合性,可以将它作为参数传递给其他selectors执行。
下面是个最基础的使用方式,可以跳转codepen来运行栗子
createSelector
createSelector
方法是Reselect的核心方法,最后一个参数默认为回调函数,其他参数可以为state、selector或数组,其中回调函数会引用其他参数作为自己的参数调用。
createSelector
实际上调用的是Reselect中叫做createSelectorCreator
的API,该API允许我们开发定制版本的createSelector
。
createSelectorCreator
被调用时会引用默认的Memoize方法来校验输入数据,在源码中叫做defaultMemoize
,该方法返回的函数就是用来判断是直接返回已经记忆的计算结果还是重新计算并返回新的结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
export function defaultMemoize(func, equalityCheck = defaultEqualityCheck) { let lastArgs = null let lastResult = null return function () { if (!areArgumentsShallowlyEqual(equalityCheck, lastArgs, arguments)) { lastResult = func.apply(null, arguments) }
lastArgs = arguments return lastResult } }
|
上面代码中的areArgumentsShallowlyEqual
方法思路很简洁,使用for循环依次比较传入的两个数组中的每一个值是否全等。
我们接下来看一下createSelectorCreator
的代码是如何使用defaultMemoize
的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
export function createSelectorCreator(memoize, ...memoizeOptions) { return (...funcs) => { let recomputations = 0 const resultFunc = funcs.pop() const dependencies = getDependencies(funcs) const memoizedResultFunc = memoize( function () { recomputations++
return resultFunc.apply(null, arguments) }, ...memoizeOptions )
const selector = memoize(function () { const params = [] const length = dependencies.length
for (let i = 0; i < length; i++) { params.push(dependencies[i].apply(null, arguments)) }
return memoizedResultFunc.apply(null, params) })
selector.resultFunc = resultFunc selector.dependencies = dependencies selector.recomputations = () => recomputations selector.resetRecomputations = () => recomputations = 0 return selector } }
|
总结
Reselect的源码很精简,阅读后能够提升对于Memoization和React优化的理解。作者在注释中多次说明使用for
代替forEach
和every
,使用arguments
而不是展开运算符是为了更快和提高性能。Reselect的官方文档阅读起来也非常的清晰和轻松,对于常见问题的解答也是很全面,这点要点赞。