反应性能优化指南
加载性能优化的目标是让用户更早地看到界面,更早地与应用程序进行交互。运行时性能优化的目标是减少堵塞,使交互更加顺畅。
我们知道React的setState会触发diff和update。默认是比较整个组件树,但是在很多情况下,diff是不必要的,因为一个子组件的props没有改变,所以不需要diff工作。
为了避免在没有改变属性的子组件上进行这种冗余的diff工作,React提供了生命周期钩子shouldComponentUpdate(下一个属性,下一个状态)。如果这个生命周期钩子返回true,它将执行下面的render和diff任务,如果返回false,React将不会继续向下。用户可以比较这个生命周期钩子中的状态和道具,以确定它是否需要更新。通常一个组件的当前props和nextProps的属性值是一样的,state的属性值也是一样的,不需要更新。
做出反应。PureComponent实现shouldComponentUpdate的方法,PureComponent采用浅层比较。
前端面试刷题网站:灵题库,收集大厂面试真题,详细分析相关知识点。
对应于类组件的PureComponent,函数组件有React.memo方法来达到类似的效果。
React .备忘录
因为默认的PureComponent和memo是默认使用的浅层比较。因此,如果对象级别很深,将会导致错过更新。
解决方法是,如果对象改变,重新创建一个对象,如果数组改变,重新创建一个数组,解构赋值,很容易实现:{...old data };[...oldArr].
用户可以实现shouldComponentUpdate来定制比较逻辑。对于功能组件,比较逻辑可以由React.memo的第二个参数定义。
如果你想准确判断区别,除了人工判断,还有一个高度自动化的方式:不可变数据,然后是不可变数据的一个JS实现:不可变-js。
只有更改过的节点会创建新的引用,所以相应的组件会执行render和diff。
结论:最佳实践是pure component/react . memo+不可变数据。
片段可以避免不必要的dom节点。
JSX的标签表达式需要一个根节点。
如果只是想让表达式返回一个标签列表,就不应该在最外层添加根节点,应该使用Fragment。
也可以缩写。
注册事件回调时,不要使用匿名函数或者绑定生成新函数。而是使用箭头函数或者在构造函数中绑定,最好是在构造函数中绑定(因为可以继承)。
当我们需要注册一个事件回调时,我们可以这样写:
或者
不推荐以上两种:匿名函数和绑定表达式。因为匿名函数的编写方法每次调用render都会创建一个新的函数,而绑定表达式每次调用也会创建一个新的函数,所以当React确实diff的时候,会解除旧函数的绑定(也会触发GC),绑定新函数。
所以,最好能做到这一点。
或者
推荐后者,因为我们知道:
类测试{ log =()= & gt;{};}和类测试{log() {}}
这两种编写方法的区别在于,前者log是类的实例方法,后者是原型方法。因此,构造函数中的绑定允许使用原型继承方法继承Test的其他组件从log方法继承。
如果使用功能组件,应该使用useCallback钩子。有关useCallback的用法,请参考知识库中的文章React Advanced。
因为React在解析JSX时需要将样式对象解析成css样式字符串。更推荐用CSS写样式。
如果在render方法中执行setState,可能会导致循环diff工作。
让条件分支只包含需要改变的元素,不包含不需要改变的元素,避免diff子节点和update节点增加不必要的操作,消耗性能。
示例:
应该这样写:
我们知道Vue有计算属性的能力,根据依赖数据计算出我们关心的数据,并且有缓存的能力:如果依赖值不变,则不需要计算,直接返回结果。
如果React想根据依赖数据计算出我们关心的数据,方法很简单。
但是,这种实现没有缓存值的能力,当计算需要很长时间时,这将影响性能。
如何实现缓存值的能力?
可以用memorial-one库:/package/memorial-one。
如果使用功能组件,可以使用useMemo来实现。关于useMemo库的使用,请参考本讲义中的文章React Advanced。
反应-虚拟化
启用并发模式时,React会采用可中断渲染,这样大规模的diff计算不会影响界面的渲染,保证渲染和交互的流畅性。
使用暂挂组件可以在加载本地组件时有更好的切换加载体验。
关于并发的详细介绍,请阅读本系列的并发模式文章。
如果不使用键或者使用索引作为键,当列表发生变化时,React无法区分前后项的对应关系,只能遍历比较更新属性,可能导致冗余操作和性能损失。
你为什么需要钥匙?我会单独写一篇文章详细解释。
React官方提供了一个性能测试工具:react-addons-perf。
这个工具可以打印出渲染React应用时各个组件的各种耗时,从而分析性能浪费。
其中一个比较重要的方法是printWasted(),它可以在不更新组件的情况下打印渲染操作。如果你发现你的组件花了很长时间渲染和diff,但是组件视图实际上并没有改变,你就要考虑是否有必要引入PureComponent来优化渲染性能。