转自:https://segmentfault.com/a/1190000006100489

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

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

React不直接操作DOM,它在内存中维护一个快速响应的DOM描述,render方法返回一个DOM的描述,React能够计算出两个DOM描述的差异,然后更新浏览器中的DOM。

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

但是,这里面有几个问题

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的组件。

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的时候假设:

1、拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件将会生成不同的树形结构。
2、可以为元素提供一个唯一的标志,该元素在不同的渲染过程中保持不变。

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>]

由于依赖于两个预判条件,如果这两个条件都没有满足,性能将会大打折扣。

1、diff算法将不会尝试匹配不同组件类的子树。如果发现正在使用的两个组件类输出的 DOM 结构非常相似,你可以把这两个组件类改成一个组件类。

2、如果没有提供稳定的key(例如通过 Math.random() 生成),所有子树将会在每次数据更新中重新渲染。

总结

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

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

React组件性能优化的更多相关文章

  1. React 组件性能优化

    React组件性能优化 前言 众所周知,浏览器的重绘和重排版(reflows & repaints)(DOM操作都会引起)才是导致网页性能问题的关键.而React虚拟DOM的目的就是为了减少浏 ...

  2. React 组件性能优化探索实践

    转自:http://www.tuicool.com/articles/Ar6Zruq React本身就非常关注性能,其提供的虚拟DOM搭配上Diff算法,实现对DOM操作最小粒度的改变也是非常的高效. ...

  3. React组件性能优化总结

    性能优化的思路 影响网页性能最大的因素是浏览器的重排(repaint)和重绘(reflow). React的Virtual DOM就是尽可能地减少浏览器的重排和重绘. 从React渲染过程来看,如何防 ...

  4. react组件性能优化PureComponent

    首先我们使用react组件会配合connect来连接store获取state,那么只要store中的state发生改变组件就会重新渲染,所以性能不高,一般我们可以使用shouldComponentUp ...

  5. 如何对react进行性能优化

    React本身就非常关注性能,其提供的虚拟DOM搭配上DIff算法,实现对DOM操作最小粒度的改变也是非常高效的,然而其组件的渲染机制,也决定了在对组件更新时还可以进行更细致的优化.  react组件 ...

  6. React Native 性能优化指南【全网最全,值得收藏】

    2020 年谈 React Native,在日新月异的前端圈,可能算比较另类了.文章动笔之前我也犹豫过,但是想到写技术文章又不是赶时髦,啥新潮写啥,所以还是动笔写了这篇 React Native 性能 ...

  7. React拖拽组件Dragact V0.1.7:教你优化React组件性能与手感

    仓库地址:Dragact手感丝滑的拖拽布局组件 预览地址:支持手机端噢- 上回我们说到,Dragact组件已经进行了一系列的性能优化,然而面对大量数据的时候,依旧比较吃力,让我们来看看,优化之前的Dr ...

  8. React组件性能调优

    React是一个专注于UI层的框架,它使用虚拟DOM技术,以保证它UI的高速渲染:使用单向数据流,因此它数据绑定更加简单:那么它内部是如何保持简单高效的UI渲染呢?这种渲染机制有可能存在什么性能问题呢 ...

  9. React项目性能优化

    1. 使用生产版本和Fragment 1. 生产版本 确保发布的代码是生产模式下(压缩)打包的代码. 一般运行npm run build命令. 直接从webpack看配置文件,需要设置mode = ' ...

随机推荐

  1. Altium Designer自动更新——解决方法

    今天,打开AD,一直显示更新,关机重启也不管事. 然后,我把AD安装目录下,system文件夹下的Installation文件夹删了.就不再更新了.

  2. 【python】闭包、@修饰符(装饰器)、

    闭包:(返回函数的行为叫闭包??) #函数也是对象,所以可以被传递 def line_conf(a,b): def line(x): return a*x+b return line line1=li ...

  3. shell 指定范围随机数抽取

  4. linux下内存泄露检测工具Valgrind介绍

    目前在linux开发一个分析实时路况的应用程序,在联合测试中发现程序存在内存泄露的情况. 这下着急了,马上就要上线了,还好发现了一款Valgrind工具,完美的解决了内存泄露的问题. 推荐大家可以使用 ...

  5. 设置Ubuntu为本地时间

    大家在切换操作系统的时候会发现一个问题, Windows 和 Ubuntu 的时间会出现不一致的情况.在 Windows 中把时间设置正确了过后,回到在 Ubuntu 后系统的时间又不一样了,在 Ub ...

  6. WebGL如何解决中文文字载入

    关于WebGL载入中文字体问题,我在网上搜了一下,发现例子并不多,而且只能实现隶书的载入,不支持其他中文字体. 下面是实现的代码: <script src="../js/three.m ...

  7. python,django做中间件屏蔽非法访问

    我使用django1.6. django框架没有urlfilter这样的原生中间件,但是灵活的django设计者为我们留下了更自由的渠道. 在没有使用django以前,我没有接触过如此潇洒的编程方式, ...

  8. C++ mem_fun 和 mem_fun_ref 的用法

    假设我们有以下的一个类: 另外有一个包含 class A 对象的数组: vector<A> vec; 如何对每一个类的对象调用成员函数print. 做法1: 利用下标 for(int i= ...

  9. DNS配置详解

    DNS简介在Linux中,域名服务(DNS)是由柏克莱网间名域(Berkeley Internet Name Domain——BIND)软件实现的.BIND是一个客户/服务系统,它的客户方面称为转换程 ...

  10. oracle xmltype导入并解析Excel数据 (五)中间表数据入库

    此处给出例子,具体根据业务需求 create or replace procedure P_CART_Sheet1(p_id in NUMBER) is--车辆管理功能v_str varchar2(4 ...