在平时开发的过程中,会应用react-redux这个中间件,但是每次更新时,不管redux中的state是否变化,都会重新更新mapStateToProps里面的值,这会造成大量冗余的操作。reselect作为redux性能优化的中间件已经在广泛使用,只有当redux中的state发生变化时,才会更新mapStateToProps中的值。下面来对其源码进行一下分析,看一下其内部是如何做到这方面性能优化的。
reselect
常用的Api是createSelector
,那就先来看一下它的源码:
createSelector
1 | export const createSelector = createSelectorCreator(defaultMemoize) |
createSelector
的源码就这一行,它调用了createSelectorCreator
方法并传入defaultMemoize
作为参数。而createSelectorCreator
也是relect
的一个Api,所以createSelector
是根据createSelectorCreator
来的,那接下来就看一下defaultMemoize
、createSelectorCreator
的源码。
在看源码之前,需要先看两个工具函数,它们起着很重要的作用:
1 | function defaultEqualityCheck(a, b) { |
这个函数很简单,就是对两个参数进行强比较。
1 | function areArgumentsShallowlyEqual(equalityCheck, prev, next) { |
这个函数也不复杂,其主要是遍历元素,然后调用equalityCheck
方法,如果有一项不满足,就会马上退出。
defaultMemoize
1 | /* |
defaultMemoize
是reselect
的核心方法,通过上面的源码分析可以知道,每次使用时,都会把参数arguments
通过闭包的方式保存起来,这样下次再调用时,可以获取到上次保存的值(也就是prevArguments),然后与本次的arguments
(也就是nextArguments)做对比,只有变化的时候,才会再次调用传入的func
方法。而这里的arguments
其实就是在mapStateToProps
中传入的参数
createSelectorCreator
1 | /* |
getDependencies方法:
1 | /* |
creatSelector实例
1 | //selector |
上面是非常简单的例子,来结合源码看一下过程:
1、根据分析,getNumA
、getNumB
、sumFn
作为createSelectorCreator
返回函数的参数funcs
传入,先将sumFn
取出,然后其他参数做是否为函数校验。
2、定义memoizedResultFunc
,其值是经过defaultMemoize
转换后的值,也就是:
1 | const func1 = function () { |
3、定义selector
,其值也是经过defaultMemoize
转换后的值:
1 | const func2 = function () { |
4、当在mapStateToProps
中调用numSum
方法并传入state
时,会执行selector
方法,所以selector
中的arguments
就是state
,在selector
内部会执行func2
方法,同时用闭包的方式保存下来arguments
,这样在getNumA
、getNumB
就会接收到state
参数,将结果放入params
数组中,执行memoizedResultFunc
传入params
5、memoizedResultFunc
内的arguments
就是传入的params
,然后执行func1
方法,也就以params
为参数执行了sumFn
,同样会用闭包保存下来arguments
,最终得到的num
就是sumFn
执行后的结果
6、此时保存了两个arguments
,一个是state
,一个是params
。只有当两个都发生变化的时候,num
才会更新,否则就一直保持原来的值
createSelectorCreator其它用法
看完源码知道,createSelector
是基于createSelectorCreator
实现的,传入的参数是defaultMemoize
,也就是reselect
内部默认的方法。但reselect
也允许自定义可配置的selector
,也就是传入createSelectorCreator
的参数可以自己选择,比如传入lodash
、underscore
中的比较、对比、缓存等方法,具体用法可以查看github文档,里面有详细介绍。
总结
经过上面的分析,createSelector
也就是createSelectorCreator
内部最主要是应用了闭包的方式,保存了之前的参数值,然后当再次调用方法传入参数的时候,会将前后两次的值进行对比,只有在发生变化的时候,才会真正调用定义selector时的方法。