查看原文
其他

[心得] 如何提高 React App 的性能

2016-09-10 Larry Lu 前端圈

台湾朋友盧承億投稿


这篇是我最近在研究React.js时的一些心得,关于怎么使用 shouldComponentUpdate 及 immutable.js 提高性能。

Virtual DOM

因为使用传统的方式对DOM 进行操作会很慢,为此React 设计了 Virtual DOM 这个中间层来降低操作 DOM 的成本。


Virtual DOM 是一个类似实际 DOM 节点的树状结构,当有数据改变时才会透过 diff 算法计算最小差异并更新到实际的 DOM 上。


所以当我们 render 时,其实都是 render 到 Virtual DOM 上,React 会自己帮我们算出最小差异然后更新。


shouldComponentUpdate

在讲 shouldComponentUpdate 之前,先来看看 Component 的生命周期。当 state 或是 props 改变的时候,会先呼叫 shouldComponentUpdate(),如果回传 true 才会 render 到Virtual DOM,最后再由React 的 diff 算法决定要怎么更新 Real DOM。


因为 shouldComponentUpdate() 预设是回传 true,也就是 “一律重绘”,所以不管有没有改变,一律重新 render到Virtual DOM 上,最后由 diff 算法判断到底哪些需要改变。


虽然 React 的 diff 算法很高效,但如果数量一多,React 要递归跑完所有component 的 render,还是会拖慢速度,所以可以自己实现shouldComponentUpdate,如果数据相同就不要重新 render。


定义一个命叫 Item的Component:

// <Item content="item1" />
var Item = React.createClass({    render(){
       return <h1> {this.props.content} </h1>;    } });

可以加入一个shouldComponentUpdate(nextProps, nextState):

shouldComponentUpdate(nextProps, nextState){
   if(this.props.content !== nextProps.content) return true;
   return false; }

只有在this.props.content改变的时候才重新 render,这样就可以大大减少重新render 的次数。

可能会遇到什么问题?

可能会遇到props是对象或者数组的情况,但对象跟数组没办法比较相等,看看下面的例子:

var obj1 = {name: 'Larry', age: 19};
var obj2 = {name: 'Larry', age: 19};

console.log(obj1 === obj2);//false
console.log(obj1.name === obj2.name && obj1.age === obj2.age);//true

var
arr1 = [1, 2, 3];
var arr2 = [1, 2, 3];

console.log(arr1 === arr2);//false

// 比較 array 內所有元素 -> true
console.log(function(){
   if(arr1.length != arr2.length) return false;
   for(var i=0 ; i<arr1.length ; i++){
       if(arr1[i] !== arr2[i]) return false;    }
   return true; }());

用===只能比较是不是同一个对象,如果要比较内容的话要自己进行比较,数组也是要自己遍历整个数组,所以shouldComponentUpdate可能会写成这样:

// <List items={['item1', 'item2', 'item3']} />

shouldComponentUpdate(nextProps, nextState){
   if(this.props.items.length != nextProps.items.length) return true;
   for(var i=0 ; i<this.props.items.length ; i++){
       if(this.props.items[i] !== nextProps.items[i]) return true;    }
   return false; }

但因为是遍历整个数组,如果数量一多的话还是会很慢,这时候就可以用immutable.js加速。

Immutable.js

immutable.js 是由Facebook 开源的一个 library,提供各种不同的结构,可以用npm install immutable安装。


比较常用的有 List 跟 Map,immutable.js 中的 List 就像是 Array

var Immutable = require('immutable');
var list1 = Immutable.List.of('a', 'b', 'c');
// ['a', 'b', 'c']
var list2 = Immutable.List.of('a', 'b', 'c');
// ['a', 'b', 'c']

console.log(Immutable.is(list1, list2));
// true
console.log(list1.get(0));
// 'a'
list1 = list1.set(0, 'b');
// list1 = ['b', 'b', 'c']
console.log(Immutable.is(list1, list2));
// false

immutable.js 中的 Map 就像是Object

var map1 = Immutable.Map({name: 'Larry', age: 19});
var map2 = Immutable.Map({name: 'Larry', age: 19});

console.log(Immutable.is(map1, map2));
// true
map1 = map1.set('name', 'Larry Lu');
// map1 = {name:'Larry Lu', age:19}

console.log(map1.get('name'));
// 'Larry Lu'
conosle.log(Immutable.is(map1, map2));
// false

这样就可以用Immutable.js来比较数组跟对象,而且Immutable.js不是把每个值都取出来比较,而是在创建 List 跟 Map 时就计算得到一个 hashvalue,比较时就比较那个 hashvalue,所以速度会快非常多。


还有一个要注意的点,immutable.js创造出来的对象是不可变的,在 js 内要更改数组内的元素只要使arr[index] = value,但用immutable.js时要使list = list.set(index,value)。因为set时不会更改原本的而是创造一个新的List,map也是一样,所以一定要使map = map.set('name','Larry Lu')。

结论

综合shouldComponentUpdate 及 Immutable.js 之后,最后就可以把 component 写成这样:

// <Item info={Immutable.Map({'name': 'Larry', age: 19})} />

var Item = React.createClass({    shouldComponentUpdate(nextProps, nextState){
       return !Immutable.is(this.props.info, nextProps.info);    },    render(){
       return (
           <div>                <h1> {'name: ' + this.props.name} </h1>                <h2> {'age: ' + this.props.age} </h2>            </div>        );    } });

这样就可以减少重新 render 的次数,而且在判断要不要重新 render 时也可以非常快速,让原本就很快的 React 变得更快。


【React启蒙系列文章】

一、[React启蒙系列] 初探React

二、[React启蒙系列] 学习React前需要理解的名词

三、[React启蒙系列] React和Babel的基本使用


【您可能感兴趣的文章】

一、手把手教你用react

二、React入门及资源指引

三、利用ESLint检查代码质量

四、构建一个安全的 JavaScript 沙箱

五、入门Webpack,看这篇就够了

六、第三届CSS大会广州找场地啦~~求介绍~~

七、Web Components 是个什么样的东西

八、JavaScript 被忽视的细节



前端圈--打造专业的前端技术会议

为web前端开发者提供技术分享和交流的平台

打造一个良好的前端圈生态,推动web标准化的发展

官网:http://fequan.com

微博:fequancom | QQ群:41378087


长按二维码关注我们

投稿:content@fequan.com

赞助合作:apply@fequan.com

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存