React组件性能优化

React: 一个用于构建用户界面的JAVASCRIPT库.html

React仅仅专一于UI层;它使用虚拟DOM技术,以保证它UI的高速渲染;它使用单向数据流,所以它数据绑定更加简单;那么它内部是如何保持简单高效的UI渲染呢?react

React不直接操做DOM,它在内存中维护一个快速响应的DOM描述,render方法返回一个DOM的描述,React可以计算出两个DOM描述的差别,而后更新浏览器中的DOM。git

就是说React在接收到props或者state更新时,React就会经过前面的方式更新UI。就算从新使用ReactDOM.render(<Component />, mountNode),它也只是看成props更新,而不是从新挂载整个组件。因此React整个UI渲染是比较快的。github

可是,这里面有几个问题

1. 若是更新的props和旧的同样,这个时候很明显UI不会变化,可是React仍是要进行虚拟DOM的diff,这个diff就是多余的性能损耗,并且在DOM结构比较复杂的状况,整个diff会花费较长的时间。算法

2. 既然React老是要进行虚拟DOM的diff,那么它的diff规则是什么?怎么利用?浏览器

PureRenderMixin

针对第一个问题React给咱们提供了 PureRenderMixin。
若是React组件是纯函数的,就是给组件相同的props和state组件就会展示一样的UI,可使用这个Minxin来优化React组件的性能。性能优化

var PureRenderMixin = require('react-addons-pure-render-mixin');
React.createClass({
      mixins: [PureRenderMixin],

      render: function() {
        return <div className={this.props.className}>foo</div>;
      }
});

ES6中的用法是数据结构

import PureRenderMixin from 'react-addons-pure-render-mixin';
class FooComponent extends React.Component {
      constructor(props) {
        super(props);
        this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
      }

      render() {
        return <div className={this.props.className}>foo</div>;
      }
}

PureRenderMixin的原理就是它实现了shouldComponentUpdate,在shouldComponentUpdate内它比较当前的props、state和接下来的props、state,当二者相等的时候返回false,这样组件就不会进行虚拟DOM的diff。框架

这里须要注意:
PureRenderMixin内进行的仅仅是浅比较对象。若是对象包含了复杂的数据结构,深层次的差别可能会产生误判。仅用于拥有简单props和state的组件。dom

shouldComponentUpdate

React虽然提供简单的PureRenderMixin来提高性能,可是若是有更特殊的需求时怎么办?若是组件有复杂的props和state怎么办?这个时候就可以使用shouldComponentUpdate来进行更加定制化的性能优化。

boolean shouldComponentUpdate(object nextProps, object nextState) {
    return nexprops.id !== this.props.id;
}

在React组件须要更新以前就会调用这个方法,若是这个方法返回false,则组件不更新;若是返回true,则组件更新。在这个方法内部能够经过nextProps和当前props,nextState和当前state的对比决定组件要不要更新。

若是对比的数据结构比较复杂,层次较深,对比的过程也是会有较大性能消耗,又可能得不偿失。
这个时候immutable.js就要登场了,也是fb出品,有人说这个框架的意义不亚于React,可是React光芒太强。它能解决复杂数据在deepClone和对比过程当中性能损耗。

注意:shouldComponentUpdate在初始化渲染的时候不会调用,可是在使用forceUpdate方法强制更新的时候也不会调用。

render

PureRenderMixin和shouldComponentUpdate的关注点是UI需不须要更新,而render则更多关注虚拟DOM的diff规则了,如何让diff结果最小化、过程最简化是render内优化的关注点。

React在进行虚拟DOM diff的时候假设:

一、拥有相同类的两个组件将会生成类似的树形结构,拥有不一样类的两个组件将会生成不一样的树形结构。
二、能够为元素提供一个惟一的标志,该元素在不一样的渲染过程当中保持不变。

DOM结构 

renderA: <div />
renderB: <span />
=> [removeNode <div />], [insertNode <span />

DOM属性

renderA: <div id="before" />
renderB: <div id="after" />
=> [replaceAttribute id "after"]

以前插入DOM

renderA: <div><span>first</span></div>
renderB: <div><span>second</span><span>first</span></div>
=> [replaceAttribute textContent 'second'], [insertNode <span>first</span>]

以前插入DOM,有key的状况

renderA: <div><span key="first">first</span></div>
renderB: <div><span key="second">second</span><span key="first">first</span></div>
=> [insertNode <span>second</span>]

因为依赖于两个预判条件,若是这两个条件都没有知足,性能将会大打折扣。

一、diff算法将不会尝试匹配不一样组件类的子树。若是发现正在使用的两个组件类输出的 DOM 结构很是类似,你能够把这两个组件类改为一个组件类。

二、若是没有提供稳定的key(例如经过 Math.random() 生成),全部子树将会在每次数据更新中从新渲染。

总结

使用PureRenderMixin、shouldComponentUpdate来避免没必要要的虚拟DOM diff,在render内部优化虚拟DOM的diff速度,以及让diff结果最小化。

使用immutable.js解决复杂数据diff、clone等问题。

参考

immutable.js

reconciliation

pure-render-mixin

相关文章
相关标签/搜索