React性能优化:reselect

项目地址:reduxjs/reselect

轮子作用:减少不必要的数据计算。

适用场景:从redux store中取数据的时候。

在一个大型的项目中,我们会在store中保存很多数据,同时也会有很多的大小组件。不同的组件需要不同的数据,所以我们保存在store中的数据往往是很完整和庞大的,在存进store之前都不会对从服务器请求回来的数据进行过多处理。

而我们每一个组件所需要的数据可能都是不同的,所以我们需要把store中的数据处理成组件所需要的数据。在这个过程中,我们可能需要遍历很多对象与数组,而这些计算在每次刷新的时候都需要进行一遍,哪怕触发刷新的是别的完全无关的操作。

reselect就是为了避免过多不必要的运算而诞生的轮子,它会缓存上次输入与输出,当它再次执行的时候会先检查一下函数的输入,如果与上次相同则避免计算,直接用上次的结果输出。

reselect还可以嵌套地写,来把一个数据变化的过程拆分成很多子过程,这些子过程也可以被别的reselect函数复用。而且任何一级的输入不变则后续的过程都会使用缓存输出。

以一个例子说明,假如我的state中有如下的数据:

state = {
    students: [
        {
            name: 'tom',
            age: 12,
        },
        {
            name: 'mike',
            age: 13,
        },
    ]
}
复制代码

我有一个组件需要用到所有学生的名单,那么reselect的写法如下:

import { createSelector } from 'reselect'

// 从state中拿出学生数据
const studentsSelector = state => state.students

// createSelector的所有参数都是函数
// 前面的函数拥有相同的输入,比如都是state
// 最后一个函数的输入是前面所有函数的输出
// 最后一个函数的输出就是reselect函数的输出
const nameListSelector = createSelector(
    studentsSelector,
    students => students.map(student => student.name)
)

nameList = nameListSelector(state) // ['tom', 'mike']
复制代码

同时我还有一个组件要用到所有学生年龄的清单,那么我们只需要写:

const ageListSelector = createSelector(
    studentsSelector,
    students => students.map(student => student.age)
)

ageList = ageListSelector(state) // [12, 13]
复制代码

我们复用了前面的studentsSelector函数,让代码得到了简化。需要注意studentsSelector并不是一个reselect函数,所以不具备缓存输入输出的能力。

后面的nameListSelector与ageListSelector则是正统的reselect函数,可以在输入相同的情况下跳过计算,直接给出缓存的结果。这样写的好处会在下面的场景中显现:

  • 如果此时我向state中添加了新的数据(比如教师档案,学生的档案并没有任何改变),那么所有从state中取数据的组件都会重新执行render函数。
  • 如果没有reselect的缓存,所有类似students.map(student => student.name)的函数都会返回新的结果,因为map方法的特性就是会返回新的数组,从而触发后续内容都的重新渲染,即使前后的map方法返回的实际内容一样,因为数组的引用变化了,所以react就会认为它变了。
  • 而使用reselect之后,因为studentsSelector这一级的输出没有变化,所以后续的输出都会使用缓存的上一次结果,这样组件就不会被重新渲染。

使用reselect函数可以很方便地完成从store数据到组件输入的转换,可以在各种重新渲染的时候避免不必要的计算从而提升性能。更加因为其复用的特性,减少了重复代码的书写,称得上是即高效又优雅。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值