众所周知,组件化是 React 的最大特性,所以我们需要关注组件的优化。
一、问题:不该重新渲染的子组件跟着别人又 render 了
我们先来看一段包含子组件的代码:
import React, { Component } from 'react';
import ColorShow from "./ColorShow";
class Example extends Component {
constructor(props){
super(props);
this.state = {
count:0
}
}
btnClick = () => {
this.setState({count:this.state.count+1})
}
render() {
return (
<div>
<h2>{`this is Immutable example , you click ${this.state.count} times`}</h2>
<button onClick={this.btnClick}>click</button>
<ColorShow />
</div>
);
}
}
export default Example;
子组件 ColorShow 的代码如下
import React, { Component } from 'react';
class ColorShow extends Component {
componentDidUpdate (){
console.log("ColorShow componentDidUpdate");
}
render() {
return (
<div >
<h2>i am show area</h2>
</div>
);
}
}
export default ColorShow;
我们在子组件 ColorShow 中的 componentDidUpdate 勾子里打印一些东西,表明在组件重新 render 了。运行如下

二、使用 PureComponent 优化
React15.3 增加 Component 的升级版 PureComponent,PureComponent 不需要我们去实现 shouldComponentUpdate 函数,它会浅比较的对比 prop 和 state 来决定组件是否需要 render。而浅比较的弊端是当 props 的结构比较复杂时,如多重对象嵌套,深层次对象的改变,这个浅比较就无法比较出来,从而阻止了组件的重新渲染。所以,PureComponent 并不能完全帮助我们在复杂数据时作出正确决策。
三、使用 Component 中的 shouldComponentUpdate 函数优化。
在组件中的 shouldComponentUpdate 函数返回 true 或 false,决定着组件是否重新 render,这就要对前后数据进行深度遍历比较,在数据的结构复杂时,这样很消耗性能。所以我们使用不可变数据 Immutable,引入 Facebook 打造了三年的 immutable.js。现在,我们来看下对比下深度遍历和不可变数据之间的性能比较。
我们会随机生成数据,使用 lodash 中 isEqual 函数进行深度遍历,看代码
//生成随机数据
let map = new Map();
for (let i = 0; i < 8000; i++) {
map.set(Math.random(), Math.random());
}
let map1 = new Map();
for (let i = 0; i < 8000; i++) {
map1.set(Math.random(), Math.random());
}
const _ = require("lodash");
//使用lodash进行深度遍历比较 map 和 map1
(function test () {
console.time("isEqual");
console.log(_.isEqual(map,map1));
console.timeEnd("isEqual");
}());
执行,比较程序的运行时间在 30ms 多。

//生成随机数据
let map = new Map();
for (let i = 0; i < 8000; i++) {
map.set(Math.random(), Math.random());
}
let map1 = new Map();
for (let i = 0; i < 8000; i++) {
map1.set(Math.random(), Math.random());
}
const {is,fromJS} = require('immutable');
//生成不可变数据
const i_map = fromJS(map);
const i_map1 = fromJS(map1);
//使用immutable中的is函数 比较两个不可变数据 i_map 和 i_map1
(function test () {
console.time("immutable_is");
console.log(is(i_map,i_map1));
console.timeEnd("immutable_is");
}());
我们先使用 fromJS 构建不可变数据,通过 is 函数比较。执行,函数执行时间在 3ms 左右。

四、总结
不可变数据 Immutable 对 React 性能的优化,这完全得益于 Immutable 的结构共享。我们目前仅从组件的角度来体现,Immutable 还有更多更好的东西值得我们研究和使用,比如和与 Redux 的搭配使用,具体大家可以参照阿里大佬camsong写的这篇详解。