React Native学习React Native

React Native 组件性能优化

2018-01-20  本文已影响283人  yuzhiyi_宇

前言

从以往的经验和实践中,我们知道影响性能最大的因素是界面的重绘,React 背后的 Virtual DOM 就是尽可能地减少重绘。
对于性能优化这个主题,我们往往会基于 "不信任" 的前提,即我们需要提高 React Virtual DOM 的效率。从 React 渲染过程看,如何防止不必要的渲染可能是最需要取解决的问题。针对这个问题,React 官方提供了一个便捷的方法来解决,那就是 PureRender。

纯函数

要理解 PureRender 中的 Pure,要从函数式编程的的基本概念 "纯函数"讲起。纯函数由三大原则构成。

对于一个方法,只要我们传入的值是固定,无论做多少次调用,结果都是一样。有些方法不依赖于你传入的参数,如 Math.random(),不传任何参数到方法中,该方法依然总是会输出不同的结果,这种方法也是纯函数。还有常用的 slice 和 splice 方法,slice在参数一致的时候结果都是一致的,splice方法的执行结果会改变原来数组,对于程序来说,splice 的隐藏行为是危险的,所以 splice 不是纯函数。

在纯函数中我们不能改变外部状态。

方法内的状态都只在方法的生命周期内存活,意味着不能在方法内使用共享变量,这会给方法带来不可知因素。

纯函数也是函数式编程的基础,他完全独立于外部状态,这样就避免了因为共享外部状态而导致的 bug。
纯函数非常方便方法级别的测试以及重构,可以让程序具有良好的扩展性及适应性。
React 就是函数式编程,React 组件本身就是纯函数,可以表示为 UI = f(data),data 包括props 和 state,改变 data,就能改变 UI,而不是像 JQuery 一样直接操纵 UI。
可以通过拆分组件为自组件,进而对组件做更颗粒度的控制。只是函数式编程的魅力之一,保持纯净状态,让方法或组件更加专注 (focused),体积更小 (small),更独立(independent),更具有复用性 (reustability)。

PureRender

pureRender 指的就是组件满足春寒书条件,即组件的渲染是被相同的 props 和 state 渲染进而得到相同的结果。

  1. PureRender 的本质

React 生命周期中有一个 shouldComponentUpdate 方法,如果返回 true,表示需要渲染,返回 false 表示不需要渲染。

  1. 运行 PureRender

React 新版本提供一个 PureComponent,PureComponent 内部重新实现 shouldComponentUpdate 方法,让当前传入的 props 和 state 与之前的作浅比较,,浅比较对 object 只作了引用比较,并没有做值比较,如果返回 false,那么组件就不会执行 render 方法。

  1. 优化 PureRender
<TestComponent 
    style={{background: 'white'}}
/>

我们可以把传入的数组或对象保存成一份引用。

<TestComponent 
    style={styles.container}
/>
const styles = StyleSheet.create({
    container: {
        background: 'white'
    },
});
onPress() {
}
<TestComponent 
    onPress={this.onPress.bind(this)}
/>

这样写,每一次渲染都会重新绑定 onPress方法, 不要让方法每一次都绑定,因此把绑定移动到构造器内。

constructor(props) {
    super(props);
    this.onPress = this.onPress.bind(this);
}

onPress() {
}

render() {
    <TestComponent 
        onPress={this.onPress}
    />
}

Immutable

在传递的数据的时候,可以直接使用 Immutable Data 来进一步提高组件的渲染性能。

  1. Immutable Data
    Immutable Data 就是一旦创建,就不能再更改的数据。对 Immutable 对象进行修改,添加或者删除操作,都会返回一个新的 Immutable 对象。Immutable 实现的原理是持久化的数据结构,也就是使用旧数据创建新数据,要保证就数据同时可用切不变。同时为了避免深拷贝把所有节点都复制一遍带来的性能损耗,Immtable 使用了结构共享,即如果对象树中一个节点发生变化,只修改这个节点和受他影响的父节点,其他节点进行共享。
  1. Immutable 的优点
  1. 使用 Immutable 的缺点
    容易与原生对象混淆。
  2. Immutable.is
    为了直接比较对象的值,Immutable提供了Immutable.is 来作"值比较"
const map1 = Immutable.Map({a: 1, b: 1})
const map2 = Immutable.Map({a: 1, b: 1})
map1 === map2; // => false
Immutable.is(map1, map2); // => true

Immutable.is比较的是两个对象的hashCode 或 valueOf (对于JS 对象),由于Immutable 内部使用 trie 数据结构来存储,只要两个对象 hashCode 相等,值就是一样的。
5.Immutable 和 PureRender
React 做性能优化最常用的就是 shouldComponentUpdate 方法,但他默认返回true,即始终会执行 render 方法,然后做 Virtual DOM比较,并得出是否需要做真实 DOM 更新,这里往往带来不必要的渲染,
当然,我们可以在 shouldComponentUpdate 中使用深拷贝和深比较来避免无必要的 render,但是深拷贝和深比较一般都是非常昂贵的选择。
Immutable.js 提供了简洁,高效的判断数据是否变化的方法,只需要 is 比较就能知道是否需要执行 render,而这个操作几乎零成本,所以可以极大提高性能。修改后的 shouldComponentUpdate 是这样的。

import React, {
    Component
} from 'react';
import Immutable from 'immutable';

class BaseComponent extends Component {

    shouldComponentUpdate(nextProps, nextState = {}) {
        return !Immutable.is(Immutable.fromJS(this.props), Immutable.fromJS(nextProps))
        || !Immutable.is(Immutable.fromJS(this.state), Immutable.fromJS(nextState));
    }
}

export default BaseComponent;

而在自定义组件你只需要继承BaseComponent,就可以拦截不必要的渲染。

class App extends BaseComponent {

}
  1. key
    写动态组件的时候,需要给动态子组件添加 key props,否则会报一个警告。Key 要保持惟一,稳定。
上一篇下一篇

猜你喜欢

热点阅读