如何有效地提高react渲染效率--深复制,浅复制,immutable原理

    xiaoxiao2021-03-25  122

    1. 性能意义:保持state不变这个约束引导我们使用局部更新对象的方法,这样会可以非常有效地提高react或其他显示框架的渲染效率。我们先来看看为了保持数据不变性,要怎么对state做更新,以我们的苹果篮子state为例:

    例子:通知开始摘苹果:apple/BEGIN_PICK_APPLE

    为了保证每个版本的state不变性,我们有两种实现方式:“深复制”,“浅复制”。我们来看两种模式的内部原理:

    深复制方式:有人会这样想:“保持state的不变性很容易,只需要深复制一个state, 让后在新的state要怎么修改就怎么修改,不ok了吗?”,如下就是深复制

    这种方式是一种很低级保持不变性的方式:

    深复制操作运行效率低

    没有为渲染环节提供提高渲染效率的铺垫

    它只是简单迎合保持数据不变性的约束,虽然有一定调试意义,但是,不但没有提高程序的性能,反而降低了程序的总体性能!没有实践意义。

    浅复制方式:浅复制模式只对内部数据发生变化的引用做更新,如下

    “state” 对象的内部数据发生变化,所以创建新的state引用;而apples array 内部数据不发生变化,所以就不对该引用做更新!在这个操作中,这种浅复制的方法运行效率比较高,而且其简单地实现了数据不变性,为调试带来方便,同时,也是更重要的,这种浅复制的方式极大地提高了视觉组件渲染阶段的运行效率!我们来对比一下:当用户点击摘苹果时,如果使用“深复制”,渲染程序需要重新遍历整个state对象树来做视觉更新,而使用浅复制来实现数据不变性时,渲染程序只需要遍历state对象的一级子节点即可,而不需要对apples array 做遍历,性能大大地提高。尤其是当苹果很多的时候,两种方式的性能差距是非常明显的。

    备注:在react组件里面,要开启条件更新这个生命周期函数 shouldComponentUpdate, 才会对把这个性能提高点释放出来,类似这样:

    ... shouldComponentUpdate(nextProps) { return nextProps.state != this.props.state; } ...

    下面我们再给出 “吃苹果” reducer 进行浅复制的例子:

    现在大家应该理解了用浅复制实现数据不变性的原理和意义了,下面我们来看具体的代码实现。

    我们的代码用 es6 编写,这里要用到 es6 两个非常方便的特性:

    Obejct.assign() 方法,该方法用于产生新的对象

    延展操作符 Spread operator : ...

    大家可以稍微看一下文档,或者看我下面的例子就知道其用法了:

    // apple basket reducer export default (state = { isPicking: false, newAppleId: 1, apples: [ { id: 0, weight: 235, isEaten: false } ] }, action) => { let newState ; switch (action.type) { case 'apple/BEGIN_PICK_APPLE': newState = Object.assign({}, state, { isPicking: true }); return newState; case 'apple/DONE_PICK_APPLE': newState = Object.assign({}, state, { apples: [ ...state.apples, { id: state.newAppleId, weight: action.payload, isEaten: false } ], newAppleId: state.newAppleId + 1, isPicking: false }) return newState; case 'apple/FAIL_PICK_APPLE': //这里只是简单处理 newState = Object.assign({}, state, { isPicking: false }); return newState; case 'apple/EAT_APPLE': newState = Object.assign({}, state, { apples: [ ...state.apples.slice(0, action.payload), Object.assign({}, state.apples[action.payload], { isEaten: true }), ...state.apples.slice(action.payload + 1) ] }) return newState; default: return state; } };

    大家会发现这种浅复制操作在开发的过程会复杂一点,于是就有了 immutable.js 这个专门处理不变性数据的库(也是facebook出品),它可以使用类似赋值的方式生成浅复制的不变性数据,下面来看看它怎么简化我们的开发:

    我们用 apple/EAT_APPLE 这个reducer来说明。

    这是原来的 reducer:

    ... case 'apple/EAT_APPLE': newState = Object.assign({}, state, { apples: [ ...state.apples.slice(0, action.payload), Object.assign({}, state.apples[action.payload], { isEaten: true }), ...state.apples.slice(action.payload + 1) ] }) return newState; ...

    这是使用 immutable.js 库的reducer :

    import { fromJS } from 'immutable'; ... case 'apple/EAT_APPLE': return fromJS(state).setIn(['apples',action.payload,'isEaten'], true).toJS(); ...

    用了immutable.js后,轻松一行代码搞定!如果团队约定 state 都用 immutable 内部的数据类型,就可以连 fromJS 和 toJS 的转化都省了,超级方便!

    到这里, reducer 任务的介绍就结束啦~

    转载请注明原文地址: https://ju.6miu.com/read-20044.html

    最新回复(0)