React常用性能优化方式整理
React组件优化
1. 属性传递优化
在动态页面中,免不了使用事件来监控按钮,React中便针对这种情况有相应的优化。以点击事件onClick为例,在React中,事件的声明方式有三种。
① 事件在声明时一起绑定:
② 使用函数式声明事件:
③ 在按钮内声明,在constructor内绑定:
三种声明方式的比较:①②相对于③,再次执行时都要再渲染一编render()里的bind函数和函数声明式,而③的绑定函数只执行一次,并不会每次执行时都进行调用,对于性能方面,显然③方式会比①②更好,而且②相对①对性能的影响会低一点。所以三者对性能优化的优先级为③>②>①。
React中,组件嵌套是十分常见的,在父组件往子组件传递对象时,应该将对象的key和value在render()内先定义再使用,不然每一次使用子组件时都会生成新的对象进行传递。
如切忌使用:
正确的用法应该是在render()内先将对象定义,再在组件中调用,如(有多种方式,只介绍其一):
在传递props/state时,只传递需要的参数。如:
切忌将props/state以展开形式传递给子组件,除非子组件需要用到父组件的所有props/state。
2. 多组件优化
在父组件因状态的变化更改,而子组件并没有状态变化时,若子组件随着父组件一起更新,会造成比较大的性能浪费,为减少子组件额外渲染而浪费性能,可使用:
① shouldComponentUpdate(nextProps, nextState):
根据React组件的生命周期可以知道,组件在每次更新状态时都会执行shouldComponentUpdate函数,为了减少额外渲染,可以在该函数内对当前的props/state与nextProps/nextState进行比较,如果有一致的props/state则返回fasle说明不用重新渲染该组件,以减少重新渲染造成的性能浪费。
② React.PureComponent 替换 React.Component:
在使用shouldComponentUpdate函数比较前后的props/state是否一致时,通常会涉及到深层或浅层的比较,在React默认进行的浅层比较中,可以使用React.PureComponent让组件根据传来的数据进行渲染而不是全部数据的渲染,这比自己写shouldComponentUpdate函数进行比较来的简单且性能更好,但只适用于组件只根据传进来的数据进行渲染而没有内部状态时使用,可以最大限度的提升性能。
③ ImmutableJS:
在比较props/state时,应使用深层比较的形式,但要手动写shouldComponentUpdate函数的深层比较需要写一个递归的函数,通过层层递归比较出当前值和next值的数据结构是否相同,这在性能方面是不可接受的,所以React建议也是默认的比较是只做浅对比,即不考虑props/state的数据结构,只考虑数值是否相同。所以在设计组件数据的传递时,不应做深层次的嵌套(如数据为对象,对象内有多个值,值内还是一个对象的形式)。而为了使组件在数据传递过程中保证渲染时当前值与next值一定是不相同的,facebook提供了immutable-js这个库,ImmutableJS提供了不可变的数据,即要让数据改变只能通过创建新数据的方式,而不能直接修改,这很大程度的降低了前后两个数据比较时的复杂度。
ImmutableJS小demo App组件(父组件):
Demo组件(子组件):
使用Immutable提供的is函数比较两个Immutable数据的数据结构是否相同
由于Immutable库比较大,所以如果在React中引用该库也是比较大的负担,有一个Immutablejs库的简易版叫做seamless-immutable,该库只支持Map,Set,List三种数据类型,但相对Immutable来说较小,对应用的负担也小。
3. Key
对于数组形式的数据,遍历时React会要求你为每一个数据值添加Key,而Key必须时独一无二的,在选取Key值时尽量不要用索引号,因为如果当数据的添加方式不是顺序添加,而是以其他方式(逆序,随机等),会导致每一次添加数据,每一个数据值的索引号都不一样,这就导致了Key的变化,而当Key变化时,React就会认为这与之前的数据值不相同,会多次执行渲染,会造成大量的性能浪费。所以只在万不得已时,才将数据的Key设为索引号。
Redux性能优化
使用reselect库:
在使用Redux进行数据的传递时,特别是经常有重复性的数据传递操作时,可以使用reselect库在内部对数据进行缓存处理,在重复调用时便可使用缓存快速加载,加强性能。
栗子(包含知识点:react-redux, connect装饰器写法):
假设在redux中创建了addAge和subAge两个action执行减1和加1。
在上述例子中,如果对小明增加和减少岁数进行重复操作,在调用到已经执行过的数据时,react不会再次对数据进行渲染,而是从reselector中取出缓存数据加载,减少了重新渲染,达到性能优化的效果。
除了以上提到的几种针对React和Redux的性能优化方案之外,还有类似于在库引用时只针对需要的模块进行引用等其他方面的优化方案,在后续的学习中,如果还有更多React优化方案也会继续添加,也欢迎大家帮忙补充。React新手,有不足之处还望海涵,也请不吝赐教,多加指正。感谢!