React性能优化
setState为什么要设计成异步?
1、用于提升性能
2、多个setState被放到队列中,最终合并成一个setState,再来渲染DOM
setState如何获取异步结果?
1、this.setState(更新的state对象,回调函数)
2、在componentDidUpdate()回调函数中获取异步更新的state
3、setState放在timeout中会变成同步
4、放到原生DOM的事件监听器中也会变成同步
setState数据的合并
当同时调用多次setState函数时,这些state最终会放入一个队列,会被合并成一个state。这些合并是后一个state覆盖前一个state。
如:setState({counter: this.state.counter + 1})
,如果重复调用3次,这里并非+3,还是加1。
如果希望每次setState都基于上次setState的值来,那么应该使用如下方式:
this.setState((preState, props) => {
return {
counter: preState.counter + 1
}
});
这里传递的是一个函数,该函数会被React框架这样调用,newState = func.call(instance, preState, props);
React更新机制到性能优化
React渲染DOM流程:JSX --> 虚拟DOM --> 真实DOM
React更新DOM流程:props/state改变 --> render函数重新执行 ——> 产生新DOM树 ——> 新旧DOM树diff --> 计算出差异进行更新 --> 更新到真实DOM
如果是两个列表DOM(li)进行diff时,如果仅仅因为顺序不同,而元素是相同的,React仍然会重新render列表中的元素,事实上这不是合理的,因为元素各自并未发送改变。
使用key解决,我们给对应的组件增加属性key=元素的唯一标识,如id。
React更新后重复渲染
当一个组件中调用了其他多个组件时,其中一个组件的state或者props发送了改变,那么会导致其他组件也会重新渲染,这显然是不合理的。
我们应该组件渲染之前,在它的生命周期函数shouldComponentUpdate(nextProps, nextState)中判断当前元素是否发生了改变,如果未发生改变,就返回false,表示不应该更新。
在React中,为我们提供了一个组件来支持这个事情,即PureComponent,它为我们重写了shouldComponentUpdate方法,它使用浅比较来进行判断。我们自己的组件只需要继承PureComponent组件即可。
如果是一个函数组件,那么我们无法使用继承PureComponent的方式来实现,在React中还为我们提供了memo函数组件,该组件内部也采用浅比较。具体用法是:
const NewComponent = memo(function OldComponent() {
return <h2>function component</h2>
});