从性能分析角度谈拆分组件
还记得前段时间关注度火爆的转转beetle吗,在惊叹着如此美妙又巧夺天工的产品思路的同时,有没有被她独特养眼却又熟悉的页面风格所吸引,在保持了页面清晰可依赖的同时我们更加追求流畅不卡顿的使用效果。转转测试部工程效率组在快速迭代开发过程中不断探索如何对组件进行合理的拆分以减少render的次数,从而提高渲染效率。
采用技术栈dva + react + ant-design
简介React借用函数式编程思想通过组件来开发应用。所谓组件,就是指能完成某个特定功能的、独立的、可重用的代码。即每个组件只关注于某一个小范围的特定功能,但是把组件排列组合起来,就能够构成一个庞大的应用。如果功能分解得足够的巧妙,那么每个组件可以在不同场景下重用,那样就不光可以构建庞大的应用,还可以构建出灵活的应用。那么当我们拿到一个多功能页面时,怎么合理解耦组件以及从什么角度来解耦呢,本文,我们旨在从性能分析的角度来解析组件的拆分。
react的性能分析React渲染分为初始化渲染和更新渲染。初始化渲染的优化可以从服务端入手,而且不管怎么拆分,主页面所有组件都需要渲染,本文从更新渲染切入主题。流程如下:
组件更新阶段的一个生命周期ShouldComponentUpdate:该生命周期默认返回true,所以一旦props和state有任何变化,都会引起所有子组件重新render。从图中可以看出,从返回true到重新渲染要经过图中红色部分,尽管react采用虚拟DOM层级对比将树形结构时间复杂度从O(n^3)降到O(n),但是依然会有大量计算过程占用浏览器内存,影响性能。
目前解决这个问题的方法有两种:PureComponent和ImmutableJS。
PureComponent只会"浅"检查组件的props和state,这就意味着嵌套对象和数组是不会被比较的。那么,掌握如何正确使用它是非常重要的,否则如果使用不当,它就无法发挥作用。
ImmutableJS对数据层级深的store是福音,但是对层级并不深的store来说就有点大材小用了。总之,合理划分组件显得尤其迫切。
合理划分出来的组件变化后的渲染效果如图(2),不合理如图(3)。
图(1)中从根组件传递下来的绿色组件上数据发生了变化
图(2)所示对应的绿色部分发生变化(只改变关键路径)
图(3)每个组件都完成了re-render和virtual-DOM diff过程,显然,这是一种浪费。
接下来,那么划分组件有哪些原则呢?
组件拆分原则:高内聚、低耦合。在react中秉承着单一原则将组件尽可能的细化,便于复用和优化,当然也要避免层级太深,传递的props太深。
尽量使拆分组件的props和state数据扁平化,最好通过继承PureComponent即可;
尽量使拆分后的组件更容易判断是否需要更新;
结合单一原则,数据扁平化,更容易判断三大特点,举例如下:
根据需求发现,Jar包详情信息和发布jar时基本信息两处都有jar包坐标展示,于是,将jar坐标的组件拆分成无状态组件,优点如下:
一方面,可以复用组件;
另一方面,无论父组件中其他的状态怎么变化,只要jarmessage的值不变,那么继承PureComponent组件的JarCoord组件就不会被重新渲染。
在后面迭代时,如果需要在发布说明这里加上一按钮,更改说明,此时点击按钮,更改说明,通过上面的分析,我们可以知道,此时父组件的重新render并不会导致JarCoord组件的重新渲染。
想了解更详细的朋友可以查看下面文章,介绍了组件的具体拆分方法以及拆分后高阶组件的合成:
https://blog.csdn.net/zhendong9860/article/details/76785242