reselect是配合redux
使用的一款轻量型的状态选择库,目的在于当store
中的state
从新改变以后,使得局部未改变的状态不会由于总体的state
变化而所有从新渲染,功能有点相似于组件中的生命周期函数shouldComponentDidUpdate
,可是它们并非一个东西。下面是官方的一些简介:javascript
- Selectors can compute derived data, allowing Redux to store the minimal possible state.
- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.
- Selectors are composable. They can be used as input to other selectors.
[注]:并非reselect
非要和redux
绑定使用不可,能够说reselect
只是一个enhancement
,并不表明强耦合。java
store
状态树庞大且层次较深我的认为符合这两点就可使用reselect
,为何?简单的state
或许根本彻底没有必要引入redux
,状态管理组件内部就能够消化,再者reselect
只是在参数级别的缓存,若是组件状态逻辑并非特别复杂,只是简单的getter
,那也可没必要引入reselect
。git
[建议]:建议引入了redux
就能够引入reselect
,去看官方的源码,总共加起来才短短的108行代码,对测试并无什么成本,同时加入也不会对打包体积形成什么影响,可是有些时候对组件渲染的性能却有很大的改善。github
这里是直接copy的官方仓库中的代码redux
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
console.log(taxSelector(exampleState)) // 0.172
console.log(totalSelector(exampleState)) // { total: 2.322 }
复制代码
const selector = memoize(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.dependencies = dependencies
selector.recomputations = () => recomputations
selector.resetRecomputations = () => recomputations = 0
return selector
复制代码
函数总体返回的就是这个selector
,由于咱们调用createSelector
,其实返回的是一个函数,因此memoize
返回的其实也是一个函数,那么selector
中作了什么?缓存
export function defaultMemoize(func, equalityCheck = defaultEqualityCheck) {
let lastArgs = null
let lastResult = null
// we reference arguments instead of spreading them for performance reasons
// 这里做为返回的函数,传入的参数即为state
return function () {
if (!areArgumentsShallowlyEqual(equalityCheck, lastArgs, arguments)) {
// apply arguments instead of spreading for performance.
lastResult = func.apply(null, arguments)
}
lastArgs = arguments
return lastResult
}
}
复制代码
memoize
是reselect
中提供的默认缓存函数,能够的得知执行这个函数的时候,返回的函数即为上面代码中的selector
,那么arguments
即为传入的state
,经过areArgumentsShallowlyEqual
比较两次传入的参数是否相等,注意,这里是浅比较,即第一层引用的比较app
function defaultEqualityCheck(a, b) {
return a === b
}
复制代码
当两次传入的值存在变化的时候,那么就会执行less
func.apply(null, arguments)
复制代码
这里会计算获得全部的依赖,而后获得下一轮缓存函数的params
。ide
就redux
的reducer
来说,这层缓存并无什么做用,看看reducer
代码:函数
function reducer(state, action) {
switch (action.type):
case REQUEST_TODO_PENDING:
return { ...state, loading: true };
case REQUEST_TODO_LIST_SUCCESS:
return { ...state, list: ['todo'], loading: false };
// ...
// default
}
复制代码
redux
社区推崇全部的state
都是不可变的,因此只要dispatch
了一个action
,每次返回的state
必然会是一个新的对象,对于浅比较每次返回的结果必然是true
;
因此,缓存的关键还在第二层momoize
,由于这里的state
并非每一次都必须变化:
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
)
复制代码
真正代码的执行在resultFunc.apply(null, arguments)
,这里缓存的逻辑跟上面没什么区别,这里就不在讲解了。resultFunc
是createSelector
中的最后一个参数
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)
)
复制代码
你们能够自行对照一下上面的这个例子,那么arguments
就是第二个函数的参数,也就是第一步缓存函数中的params
。
好了,就啰嗦这么多了,最后,多读书,多看报,少吃零食,多睡觉😪😪💤