React性能优化心得
本文是《深入React技术栈》读书笔记,其中的很多都已经运用到实际项目中
更多笔记可以star我的github,上面基本都是平时的学习笔记,以及项目中的实践心得,欢迎关注
影响网页性能一个较大的因素是浏览器的重绘reflow
和重排版repaint
。
我们通过拆分组件为子组件,进而对组件进行更细粒度的控制。这也是函数式变成的魅力之一,保持纯净的状态;可以让方法和组件更加专注,体积更小,更独立,更有复用性和测试性
PureRender的本质
官方提供了react-addons-pure-render-mixin
的插件,其原理为重新实现shouldComponentUpdate
的方法,当前的state
和props
与之前做浅比较,如果返回fales
,就不会调用render
方法
但是默认的shouldComponentUpdate
方法是默认的深比较。但是深比较的代价十分昂贵,就如下面的代码
shouldComponentUpdate(nextProps, nextState) {
return isDeepEqual(this.props, nextProps) && isDeepEqual(this.state, nextState);
}
然而PureRender
只对值进行了浅比较,以下是shollowEqual
的示例代码
function shallowEqual(obj, newobj) {
if(obj === newobj) {
return true;
}
}
const objkeys = Object.keys(obj);
const newobjkeys = Object.keys(newobj);
if(objkeys.length !== newobjkeys.length) {
return false;
}
// 以下是关键代码
return objkeys.every(key => {
return newobj[key] === newobjkeys[key];
})
运用PureRender
利用createClass
构建组件时,可以使用官方插件react-addons-pure-render-mixin
import PureRenderMixin from \'react-addons-pure-render-mixin\';
class App extends Component {
constructor(props) {
super(props);
this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
}
return <div className={this.props.className}>foo</div>
}
优化PureRender
- 直接将props设置为对象或者数组
我们知道,每次调用React组件其实都会重新创建组件。就算传入的数组或对象的值没有改变,他们引用的地址也会改变
<Account red\'}} />
这样设置的props每次渲染都会创建新对象。这样的操作,我们只需要提前将其赋值为常量,不直接使用字面量即可
const defaultStyle = {};
<Account | defaultStyle} />
- 设置props方法并通过事件绑定在元素上面
// 事件绑定写入到构造函数中
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
- 设置子组件
const NameItem = () => <Item><span>Arthur</span></Item>;
// 上面的组件翻译过来其实是
const NameItem = () =>
<Item
children={React.createElement(\'span\', {}, \'Arthur\')}
/>
显然上面Item组件不管什么情况下都会直接渲染,那么如何避免这种情况
import React, {Component} from \'react\';
import PureRenderMixin from \'react-addons-pure-render-mixin\';
class NameItem extends Component {
constructor(props) {
super(props);
this.shouldComponentUpdata = PureRenderMixin.shouldComponentUpdate.bind(this);
}
render() {
return (
<Item><spanArthur</span>></Item>
)
}
}
Immutable
Immutable Data
就是一旦被创建,就不能更改的数据,对Immutable Data
对象进行修改添加或者删除操作,都会返回一个Immutable
对象,实现的原理就是持久化数据结构。
Immutable
使用旧数据创建新数据时,要保证旧的数据可用但是不可变,同时为了避免将所有的节点都复制一遍带来的性能损耗,Immutable
使用结构共享,即如果对象树中一个节点发生变化,只修改这个节点和它受影响的父节点
- Map 键值对的集合,对应于Object,ES6也有专门的Map对象
- List 有序可重复对象,对应于Array
- ArrayList 无序不可重复列表
Immutable.is
为了直接比较两个对象的值,可以使用Immutable.is
来作比较
let map1 = Immutable.Map({a: 1, b:2});
let map2 = Immutable.Map({a: 1, b:2});
Immutable.is(map1, map2); // true
Immutable.is比较的是两个对象的hashCode或valueOf,由于immutable内部使用了trie数据接口来存储,只要两个对象的hashCode相等,值就是一样的,这样做的效率非常之高
react-addons-create-fragment
当有两个子组件需要渲染时,我们没办法给他设置key。这个时候可以使用官方提供的插件
import React, {Component} from \'react\';
import {render} from \'react-dom\';
import createFragment from \'react-addons-create-fragment\';
const first = <li>first</li>;
const second = <li>second</li>;
const Rank = ({first, second}) => {
const children = createFragment({
first,
second
});
return <ul>{children}</ul>;
};
render(<Rank first={first} second={second} />, document.getElementById(\'app\'))