React在进行渲染的时候会经历初次渲染和更新渲染,首次渲染是没有真实的DOM操作快的,在更新渲染的时候,通过Virtual DOM,DOM Diff
比真实的DOM操作快,但是也存在需要优化的情况
比如:我们更新了图中DOM树第3层的一块(绿色),我们希望渲染的是DOM树的最短路径(绿色部分),但是React的默认做法的调用所有子组件的render,再与生成的虚拟DOM进行对比,如果不变则不更新,这里不变(黄色部分)的渲染和对比是需要优化的部分
两个性能优化点
- 父组件更新默认触发所有子组件更新
- 列表类型的组件默认更新方式非常复杂
解决方法
- 子组件执行
shouldComponentUpdate()
,自行决定是否更新,React的优化是基于shouldComponentUpdate
的,该生命周期默认返回true,所以一旦prop或state有任何变化,都会引起重新render - 给列表中的组件添加
key
属性,不要使用默认的index
,因为一旦数组的索引发生变化,会触发不必要的更新
详解
React 针对组件的shouldComponentUpdate()
进行了封装处理
React ES5提供了PureRenderMixin
的mixin
形式
import PureRenderMixin from 'react-addons-pure-render-mixin';
class FooComponent extends React.Component {
constructor(props) {
super(props);
this.shouldComponentUpdate =
PureRenderMixin.shouldComponentUpdate.bind(this);
}
}
React ES6新增了一个PureComponent
类,以 ES6 class 的方式方便地定义纯组件(pure component)
,用于取代之的PureRenderMixin
用法是把继承类从Component
换成PureComponent
即可,当组件更新时,如果组件的props,state
都没发生改变,就不会触发render
,省去了 Virtual DOM 的生成和比对过程,达到提升性能的目的
import React, { PureComponent } from 'react'
class Example extends PureComponent {
render() {
...
}
}
这里要注意的是:PureRenderMixin、PureComponent
内进行的仅仅是浅比较对象(shallowCompare)
,如果我们的state
变为
state = {
value: { foo: 'bar' }
}
// 每次更改value值的时候进行:
this.setState({ value: newValue });
此时直接通过值的比较是行不通的,因为对象的引用关系,导致在子组件里面接受到的this.props.value 与 nextProps.value
永远都是相等,就不会更新
解决方法
- 深比较: 原理与深拷贝类似,比较耗时,不推荐
- immutable.js:FaceBook官方提出的不可变数据解决方案,主要解决了复杂数据在deepClone和对比过程中性能损耗
总结
-
immutable.js
的思想其实是跟React的虚拟DOM是一致的,都是为了减少不必要的消耗,immutable.js
减少对象占用内存,虚拟DOM减少了浏览器的重绘和重排版
React性能检测工具 react-addons-perf
import Perf from 'react-addons-perf'
window.Perf = Perf // 挂载到全局变量方便使用
检测方法,在浏览器控制台输入如下命令
开始记录:Perf.start()
结束记录:Perf.stop()
打印结果:printInclusive()
参考文章推荐
React组件性能调优