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组件进行了一系 ...
随机推荐
- 【Luogu P1048 Luogu P1016】采药/疯狂的采药
采药/疯狂的采药 两道模板题,分别是0-1背包和完全背包. 0-1背包 二维:dp[i][j]=max(dp[i-1][j-time[i]]+v[i],dp[i-1][j]); 由于i的状态由i-1的 ...
- 实现自定义的参数解析器——HandlerMethodArgumentResolver
1.为什么需要自己实现参数解析器 我们都知道在有注解的接口方法中加上@RequestBody等注解,springMVC会自动的将消息体等地方的里面参数解析映射到请求的方法参数中. 如果我们想要的信息不 ...
- DPT-RP1 解锁过程整理
前言 首先,感谢大神HappyZ ,没有他的教程,没有下文了. 其次,要感谢的是润物 ,没有她的教程, 可能要研究好久才能弄明白大神给的工具怎么用. 本人没接触过python,以为在命令行执行Pyth ...
- 程序员的进阶课-架构师之路(14)-B+树、B*树
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...
- CSRF(Cross-site request forgery)跨站请求伪造
CSRF是什么 CSRF(Cross-site request forgery)跨站请求伪造,也被称为"One Click Attack"或者Session Riding,通常缩写 ...
- MySql简单的增删改查语句 js
最近在项目中需要连接数据库,做增删改查的功能,sql语句整理做了以下记录(基于NodeJs,注:data为你的真实数据): (一)新增插入表中数据: sql: 'insert into work(表名 ...
- stream,做减法,优化搜索代码。
做一个搜索,三个输入条件,求这个条件的交集.起初我的思路是按照操作的流程,一步步的来做这三个筛选. let searchResults = []; //step1 根据id搜索,得到一个子集. if ...
- 【nodejs原理&源码赏析(2)】KOA中间件的基本运作原理
[摘要] KOA中间件的基本运作原理 示例代码托管在:http://www.github.com/dashnowords/blogs 在中间件系统的实现上,KOA中间件通过async/await来在不 ...
- gitbook 入门教程之自定义不一样的多语言首页插件
自定义多语言主页 中文 | English
- 剑指offer-31:整数中1出现的次数(从1到n整数中1出现的次数)
参考: https://troywu0.gitbooks.io/interview/整数中出现1的次数(从1到n整数中1出现的次数).html 题目描述 求出1~13的整数中1出现的次数,并算出100 ...