React 性能调优总结

React 性能调优总结

首先要说一个库: why-did-you-update, 地址:why-did-you-update, 利用这个库能够在页面上快速看到多余渲染的问题:git

由于多数状况下咱们在React组件当中是不会去写shouldComponentUpdate这个hook来避免多余渲染的,因此就形成了少许的性能浪费。虽然优化是个漫长的道路,过早优化是邪恶的,但作仍是要去作的。es6

下面讲一下基本的一些手段github

shouldComponentUpdate

在React当中,每一次的setState操做,都会让Virtual DOM去作diff操做,虽然虚拟DOM的计算很快,可是随着组件愈来愈多,结构愈来愈复杂,当你改变某个简单的state时,就会形成连带不少Component的从新render,因此咱们能够在组件内部去添加shouldComponentUpdate钩子来告诉React是否要更新组件redux

PureComponent

固然咱们在实际开发过程中,因为数据的复杂程度来讲,基本是不会去写shouldComponentUpdatehook,这时就能够去使用PureComponent类来声明组件。数组

PureComponent的前身是PureRenderMixin,和Component的区别就在于组件在render以前会自动执行一次shallowEqual(浅比较),就至关于组件的第一层props和state的数据若是没有发生改变,render就不会去执行,从而减小了没必要要的渲染。数据结构

根据React源码,若是组件是纯组件(Pure Component),那么一下比较是很容易理解的:闭包

if (this._compositeType === CompositeTypes.PureClass) { shouldUpdate = !shallowEqual(prevProps, nextProps) || ! shallowEqual(inst.state, nextState); } 

为何说是浅比较呢?这个很好理解,js的引用数据类型就很好的说明了这一点:app

{} === {} //false [] === [] //false 

固然,你也能够在shouldComponentUpdate中本身来写深比较,在数据结构相对简单的状况下:函数

shouldComponentUpdate(nextProps, nextState) {
  return nextProps.user.id === props.user.id; } 

若是是在PureComponent当中写了这个钩子,那么它就会被优先执行。性能

固然,在数据结构和嵌套比较深的状况下,这个方案也就不太管用了,因此,咱们在前期定义数据结构时也是一个很重要的环节,能够去避免没必要要的渲染。

Immutable or Immer

Facebook在2014年就推出了这个库: Immutable.js,用来使数据持久化。在数据建立后,就不得去改变,任何的增删改操做都是true一个新的Immutable对象:

import { Map } from "immutable"; const map1 = Map({ a: { aa: 1 }, b: 2, c: 3 }); const map2 = map1.set('b', 50); map1 !== map2; // true map1.get('b'); // 2 map2.get('b'); // 50 map1.get('a') === map2.get('a'); // true 

ImmutableJS 最大的两个特性就是: immutable data structures(持久性数据结构)与 structural sharing(结构共享),持久性数据结构保证数据一旦建立就不能修改,使用旧数据建立新数据时,旧数据也不会改变,不会像原生 js 那样新数据的操做会影响旧数据。而结构共享是指没有改变的数据共用一个引用,这样既减小了深拷贝的性能消耗,也减小了内存。好比下图:

ImmutableJS的API过于复杂,并且我也没有用redux,而是采用了MutableMobx,看见Mobx的做者写了一个库Immer,相对于ImmutableJS 比较简单:

import produce from "immer" /** * Classic React.setState with a deep merge */ onBirthDayClick1 = () => { this.setState(prevState => ({ user: { ...prevState.user, age: prevState.user.age + 1 } })) } /** * ...But, since setState accepts functions, * we can just create a curried producer and further simplify! */ onBirthDayClick2 = () => { this.setState( produce(draft => { draft.user.age += 1 }) ) } 

代码上的优化

少用bind

每次bind都会返回一个新函数,重复建立静态函数会浪费性能。最好直接使用箭头函数绑定或者利用闭包直接把处理函数传入子组件

setState优化

在咱们去setState时,最好用新值去覆盖旧值,而不是修改原值。 对于数组,咱们采用es6的spread语法:

this.setState(prevState => ({ words: [...prevState.words, 'marklar'], })); 

对于对象,咱们采用Object.assign或spread:

this.setState({ a: Object.assign({}, this.state.a, {b: '2222'}) }) //或者 this.setState({ a: {...this.state.a, {b: '222'}} }) 

不要在PureComponent组件的props使用直接赋值的方式

style={ { width: '100px' } } 这样的作法传入组件会形成重复渲染

这样的方式会使shallowEqual必定返回false

正确的方式:

const YourStyle = { width: '100px' } return ( <YourComponent style={YourStyle}></YourComponent> ) 

或者咱们直接就用上面说到的Immutable.js 或者 Immer.js 来处理

相关文章
相关标签/搜索