React项目性能优化

570 阅读6分钟

一、前言

性能优化,是个老生常谈的话,那么在react项目里面,我们可以做些什么来优化我们页面的性能呢,本文将从几个角度来具体的进行性能优化。

二、性能分析工具

工欲善其事,必先利其器。 我们要是想去优化的话,必须得有个工具去检测性能,看看到底是哪里出了问题,react16.5及以上的版本可以通过浏览器的 Profiler 来进行分析性能,16.5及以下的可以通过performance来查看。

  1. 点击左上角蓝色的小圈圈开始录制,左上角第三个按钮是清除之前的 截屏2022-05-17 下午6.49.25.png
  2. 录制结束之后,点击结束

截屏2022-05-17 下午6.58.15.png 3. 可以勾选这里的第一条,这样后面就可以查看到为什么会渲染页面了

截屏2022-05-17 下午7.19.33.png 4. 经过以上步骤,就可以看到当前页面所有的组件,Flamegraph展示的是当前页面的组件,Ranked是按照渲染时间的长短来将组件排序,下图可看出,当前组件为Template,里面包含TableFilter,UTable,TemplateModal,DetailDraw等组件,还能看出包含组件的渲染时间,这对我们分析组件有很大的帮助。

截屏2022-05-17 下午7.25.06.png 5. 第三步勾选了之后,右边就会出现渲染的原因,能帮助我们更好的找到为什么组件重新渲染了。

截屏2022-05-17 下午7.28.23.png

三、优化方法

1、React.memo

原因:有时候父组件更新自己状态的时候,子组件不需要重新渲染,因此把子组件用React.memo包裹,让子组件不会因为父组件的变化而重新渲染。

截屏2022-05-17 下午8.36.05.png 没加memo:

截屏2022-05-17 下午8.36.57.png

截屏2022-05-17 下午8.37.42.png 加了memo:

截屏2022-05-17 下午8.38.32.png

截屏2022-05-17 下午8.38.54.png 上面对比可看出,加了memo之后,改变color,Test文件不会再被渲染(灰色表示没有渲染)。

2、useMemo

原因:有时候组件内部需要大量的计算,那么这个时候可以通过useMemo来缓存这些计算,useMemo返回的是一个数值。

截屏2022-05-17 下午9.46.11.png

3、useCallback

原因:useCallback主要用于避免子组件不必要的重新渲染,有时候父组件给子组件传递一个函数,然后父组件自身的state变化的时候,父组件会重新渲染,传递给子组件的函数会变成一个新的,就算这个时候用React.memo包裹住,由于props变化了,那么子组件也会重新渲染,因此这里我们可以把父组件传递的函数用useCallback包裹,然后配合React.memo可以避免子组件的多次重复渲染。useCallback返回的是一个函数。

截屏2022-05-17 下午10.18.34.png

截屏2022-05-17 下午10.18.53.png

4、加入防抖和节流

原因:防抖和节流可以减少因为用户的重复操作而导致页面出现很多无用的渲染。

截屏2022-05-17 下午10.54.29.png

截屏2022-05-17 下午10.55.01.png

5、避免添加额外的元素和内联样式

原因:因为react要求创建的时候必须要有一个父元素,如果DOM元素写多了,渲染的时间也会加长,这时候可以通过<>或者React.Fragment来创建空的元素。

截屏2022-05-17 下午10.39.24.png

截屏2022-05-17 下午10.39.38.png

6、合理拆分组件

原因:当一个页面上很多内容的时候,当前页面如果状态变化了,那么这个页面上很多方法以及内容都会重新生成,增加了渲染的时间,那么此时把这个页面上很多内容都拆分为一个一个的小组件的时候,可以避免某些状态的变化而导致整个页面的重新渲染。

7、组件懒加载

原因:在 SPA 中,懒加载优化一般用于从一个路由跳转到另一个路由。还可用于用户操作后才展示的复杂组件,比如点击按钮后展示的弹窗模块。React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 default export 的 React 组件,Suspense里面的fallback可以用来做降级处理。 截屏2022-05-17 下午11.21.54.png

8、组件懒渲染

原因:组件懒渲染,可以让组件在可视区域内再展示,常见组件有弹框组件以及抽屉组件,就是让当前组件需要展示的时候,再进行展示。那么如何判断是否在当前可视区域呢?可以利用Element.getBoundingClientRect()方法或者react-intersection-observer第三方插件来辅助。

9、虚拟长列表

原因:有时候需要展示的数据过多,一次展示完会加重页面的渲染负担,那么此时我们可以引入虚拟长列表,只展示当前可视区域内的数据,虚拟长列表有很多种实现方案,可以自己写一个简单的,也可以直接引入第三方插件。

截屏2022-05-18 上午10.17.05.png

10、静态资源使用CDN

原因:没有使用CDN的时候,浏览器要将域名解析为 IP 地址,所以需要向本地 DNS 发出请求,本地 DNS 依次向根服务器、顶级域名服务器、权限服务器发出请求,得到网站服务器的 IP 地址, 本地 DNS 将 IP 地址发回给浏览器,浏览器向网站服务器 IP 地址发出请求并得到资源。使用CDN的时候,浏览器要将域名解析为 IP 地址,所以需要向本地 DNS 发出请求,本地 DNS 依次向根服务器、顶级域名服务器、权限服务器发出请求,得到全局负载均衡系统(GSLB)的 IP 地址,本地 DNS 再向 GSLB 发出请求,GSLB 的主要功能是根据本地 DNS 的 IP 地址判断用户的位置,筛选出距离用户较近的本地负载均衡系统(SLB),并将该 SLB 的 IP 地址作为结果返回给本地 DNS,本地 DNS 将 SLB 的 IP 地址发回给浏览器,浏览器向 SLB 发出请求,SLB 根据浏览器请求的资源和地址,选出最优的缓存服务器发回给浏览器,浏览器再根据 SLB 发回的地址重定向到缓存服务器,如果缓存服务器有浏览器需要的资源,就将资源发回给浏览器。如果没有,就向源服务器请求资源,再发给浏览器并缓存在本地。

11、图片压缩

原因:一般图片都比较大,上传也会比较慢,在网站对图片要求质量不高时,可以将图片先压缩,再上传。或者将图片延迟加载,判断图片出现在当前可视区域了,再将图片的src替换为真正的地址。