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

来源:互联网 发布:2016年淘宝双十一数据 编辑:程序博客网 时间:2024/06/05 00:21

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

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

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

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

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

  1. 深复制操作运行效率低

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

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

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

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

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

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

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

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

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

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

  2. 延展操作符 Spread operator : ...

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

// apple basket reducerexport 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 任务的介绍就结束啦~

0 0
原创粉丝点击