reselect是怎样提升react组件渲染性能的?
reselect是什么?
reselect是配合redux使用的一款轻量型的状态选择库,目的在于当store中的state重新改变之后,使得局部未改变的状态不会因为整体的state变化而全部重新渲染,功能有点类似于组件中的生命周期函数shouldComponentDidUpdate,但是它们并不是一个东西。下面是官方的一些简介:
- 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,并不代表强耦合。
什么时候用reselect?
store状态树庞大且层次较深- 组件中的state需要经过复杂的计算才能呈现在界面上
个人认为符合这两点就可以使用reselect,为什么?简单的state或许根本完全没有必要引入redux,状态管理组件内部就可以消化,再者reselect只是在参数级别的缓存,如果组件状态逻辑并不是特别复杂,只是简单的getter,那也可不必引入reselect。
[建议]:建议引入了redux就可以引入reselect,去看官方的源码,总共加起来才短短的108行代码,对测试并没有什么成本,同时加入也不会对打包体积造成什么影响,但是有些时候对组件渲染的性能却有很大的改善。
基本用法
这里是直接copy的官方仓库中的代码
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 }
reselect是怎么优化代码性能的?
- 整体store层级state的缓存
- 组件级别state的缓存
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比较两次传入的参数是否相等,注意,这里是浅比较,即第一层引用的比较
function defaultEqualityCheck(a, b) {
return a === b
}
当两次传入的值存在变化的时候,那么就会执行
func.apply(null, arguments)
这里会计算得到所有的依赖,然后得到下一轮缓存函数的params。
就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。
总结
好了,就啰嗦这么多了,最后,多读书,多看报,少吃零食,多睡觉
reselect是怎样提升react组件渲染性能的?的更多相关文章
- react+redux渲染性能优化原理
大家都知道,react的一个痛点就是非父子关系的组件之间的通信,其官方文档对此也并不避讳: For communication between two components that don't ha ...
- React + Reflux 渲染性能优化原理
作者:ManfredHu 链接:http://www.manfredhu.com/2016/11/08/23-reactRenderingPrinciple 声明:版权所有,转载请保留本段信息,否则请 ...
- 使用CSS3开启GPU硬件加速提升网站动画渲染性能
遇到的问题: 网站本身设计初衷就没有打算支持IE8及以下版本浏览器,并不是因为代码兼容性问题,而是真的不想迁就那些懒得更新自己操作系统和浏览器的用户,毕竟是我自己的网站,所以我说了算!哈哈~ 没有了低 ...
- 相当有用的react+redux渲染性能优化原理
学习地址:http://foio.github.io/react-redux-performance-boost/
- React组件性能调优
React是一个专注于UI层的框架,它使用虚拟DOM技术,以保证它UI的高速渲染:使用单向数据流,因此它数据绑定更加简单:那么它内部是如何保持简单高效的UI渲染呢?这种渲染机制有可能存在什么性能问题呢 ...
- React组件性能优化
转自:https://segmentfault.com/a/1190000006100489 React: 一个用于构建用户界面的JAVASCRIPT库. React仅仅专注于UI层:它使用虚拟DOM ...
- 从性能角度看react组件拆分的重要性
React是一个UI层面的库,它采用虚拟DOM技术减少Javascript与真正DOM的交互,提升了前端性能:采用单向数据流机制,父组件通过props将数据传递给子组件,这样让数据流向一目了然.一旦组 ...
- React 组件性能优化探索实践
转自:http://www.tuicool.com/articles/Ar6Zruq React本身就非常关注性能,其提供的虚拟DOM搭配上Diff算法,实现对DOM操作最小粒度的改变也是非常的高效. ...
- React组件:拖拽布局Dragact v0.1.6 发布
仓库地址:Dragact爽滑的拖拽组件 大家好,新年已经过去,大家又投入了繁忙的工作当中,由于我在国外,因此压根儿没有休息... 少说废话,上周一周的时间里,我陆陆续续的为Dragact组件进行了一系 ...
随机推荐
- matlab-汉字unicode编码转换
str='黑大哥'bianma=unicode2native(str); disp(bianma); pp=native2unicode(bianma);disp(pp)
- jquery浅复制和深复制区别
jquery浅复制和深复制区别
- 请求库urllib和urllib3
# coding=utf-8 # urllib """ 使用python的urllib库去模拟浏览器请求网页,常用内容如下: urllib.request 发送HTTP请 ...
- 【搞定面试官】你还在用Executors来创建线程池?会有什么问题呢?
前言 上文我们介绍了JDK中的线程池框架Executor.我们知道,只要需要创建线程的情况下,即使是在单线程模式下,我们也要尽量使用Executor.即: ExecutorService fixedT ...
- @NotEmpty、@NotNull、@NotBlank注解解析
源码解析 @NotEmpty根据JDK源码注释说明,该注解只能应用于char可读序列(可简单理解为String对象),colleaction,map,array上,因为该注解要求的是对象不为null且 ...
- Prometheus Label 标签管理
目录 前言 配置测试 删除metric值 重新加载配置文件后测试 更换 重新加载配置文件后测试 删除 Label 标签 前言 在prometheus监控体系中.标签label是一个极为重要的参数,考虑 ...
- 环境变量PATH、cp命令、mv命令、文档查看cat/more/less/head/tail 各个命令的使用介绍
第2周第2次课(3月27日) 课程内容: 2.10 环境变量PATH2.11 cp命令2.12 mv命令2.13 文档查看cat/more/less/head/tail 2.10 环境变量PATH P ...
- 你知道,HTTPS用的是对称加密还是非对称加密?
1.引言 随着互联网安全意识的普遍提高,对安全要求稍高的应用中,HTTPS的使用是很常见的,甚至在1年前,苹果公司就将使用HTTPS作为APP上架苹果应用市场的先决条件之一(详见<苹果即将强制实 ...
- 阿里巴巴 Service Mesh 落地的架构与挑战
点击下载<不一样的 双11 技术:阿里巴巴经济体云原生实践> 本文节选自<不一样的 双11 技术:阿里巴巴经济体云原生实践>一书,点击上方图片即可下载! 作者 | 方克明(溪翁 ...
- 解决 Docker Hadoop ssh "Connection to * closed".问题
Docker 最近很火, 可以快速轻量级地虚拟出多个node,所以打算在Docker中跑Hadoop伪分布式应用. 其实要做出个简单的版本倒是不难,主要在 建立ssh无密码登录本机时,出现刚登录上去, ...