这篇是我最近在研究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.jsimmutable.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://
|