文章目录
1 优化原则
不要过早对项目进行优化
切勿浪费精力在对整体性能提高的不多的代码上
对于关键的性能点尽早优化
react使用虚拟dom树提高性能,每次渲染并非抛弃所有重新渲染,而是借助虚拟dom计算dom树的最小修改
优化点:在计算前就判定是否需要去重新渲染
2 常用手段
使用shouldComponentUpdate
来判定是否需要重新渲染是最常用的手段
2.1 单个React组件优化
- 在构造函数中绑定this
对于回调函数有三种方法进行绑定:构造中、render中、箭头函数,三种方法中只有构造函数是只执行一次的(箭头函数也可以)。尽量少在render中绑定回调,因为每次绑定,对于被绑定的组件来说,传入的回调函数都是一个新对象,都会造成子组件重新渲染。
// render中绑定回调,当父组件重新渲染时,子组件一定会重新渲染
...
render(){
return <A onClick={()=>{console.log(1)}} />
}
...
- render中的参数尽量使用同一对象
由于react判定是否需要重新渲染,是通过浅层比较(地址比较)来判断的,对于值类型的变量来说没什么问题,对于引用类型的来说需要确保每次都是传入的原来的对象,否则造成性能浪费,如:
<Foo style={{color: 'red'}} />
传入的是一个对象,而每次render时该对象都是一个新的对象,会被react认为Foo组件的props每次render均发生变化,建议使用:
const fooStyle = {color: 'red'}
<Foo style={fooStyle} />
- 列表数据使用单独组建进行渲染
由于列表元素渲染非常耗时,即使列表元素未发生改变,react在比较新旧列表元素时依然需要花费大量时间,建议将列表元素包装为一个组件进行单独渲染
// 新旧比较花费大量时间
{x.map(item=><p>item</p>)}
// 包装成组件后
<X content={x}/>
const X = props => <div>{props.content.map(item=><p>item</p>)}</div>
2.2 shouldComponentUpdate解析
react默认每次更新都会调用所有的生命周期函数,所以如果没有重写该周期函数,默认是直接返回true
react渲染规则:
从React组件的根节点开始依次按照该规则进行检查
- 当前节点检查scu为true,则会进行vDOMEq比较,如果比较结果为一致就停止更新,否则向下进行遍历
- 当前节点检查scu为false,直接停止该节点更新
起始相当于双保险:一个是scu的true和false,另一个是vDOMEq的true和false,任一为false,都会让该节点不更新,只有两个都为true才会更新该节点
2.3 PureComponent
由于大多数情况下只需要对比state和props来判断是否需要更新,所以PureComponent类实现了自己的更新方法,自动的浅比较state和props来判断是否需要更新
特别注意:对于state或props中包含引用数据类型的无法判断是否被改变了!!
如:
import React, { PureComponent } from 'react'
class MyTest2 extends PureComponent {
constructor(props) {
super(props);
this.state = {
arr: []
}
}
add1 = () => {
let arr = this.state.arr
arr.push(1)
this.setState({ arr })
}
// shouldComponentUpdate() {
// }
render() {
console.log('update')
return (
<div>{this.state.arr.length}<button onClick={this.add1}>click2</button></div>
);
}
}
export default MyTest2;
该组件单击后无任何变化,虽然state中的arr已经被改变了,但是页面不会被重新渲染
2.4 使用immutable(ImmutableJS)
待补充
3 其他优化点
- 慎用展开语法
{...this.props}
,该语法会创建一个新对象,同时传递很多当前组件不需要的参数 - 在构造中进行函数this绑定
- 复杂页面尽量拆分
- 对于不变的展示组件使用const element
- map必须要添加key
- props和state尽量扁平化
- 使用return null来控制组件的显隐,而不是css的display:none
- 对于mobx+react来说,尽可能晚的解引用,能防止引用的属性变化导致父组件重渲染,进而自组建重渲染(由于mobx会观测当前组件可观测属性的变化,解引用早了,该引用变化会引起当前组件重渲染,并可能引起子组件重渲染)
// personStore中的name发生变化
// 早解引用
<A a={personStore.name}/>
// 晚解引用
<A a={personStore}/>