性能优化

一份完整的「前端性能优化」手册

性能衡量指标

LCP
INP
react组件重新渲染次数

React性能优化

React的性能优化本质上是 减少进入rerender流程 以及 进入rerender流程后减少组件更新,剪枝

引起一个组件重新渲染的原因有: state变化,父组件rerender,context变化,hooks变化

只要父组件rerender就会引发子组件rerender,除非子组件用了memo,而此时才能说props变化引发了子组件rerender

React.memo

React.memo 包裹复杂组件,要传递给该组件的 对象 函数 分别用 useMemo useCallback 包裹

内部机制

memo 对新旧props进行浅比较,返回false时代表新旧props不同,该函数组件才会被再次调用更新

memo必须和useMemo/useCallback一起使用

父组件执行时,内部创建的 function/object 每次都是新的,作为props传递给memo包裹的组件时,每次都会被判定成false

因此,父组件要传递给memo子组件的 function/object 必须用 useMemo/useCallback 包裹,否则无意义。

将复杂组件额外封装

避免其他属性的变更导致复杂组件也重新渲染

多个state更新尽量一次性同步更新

react17中,异步请求返回的多组数据,统一调用 unstable_batchedUpdates,react18自动批处理

非影响视图的数据用ref而非state储存

使用context进行跨组件传递

不通过props进行层层传递,以保证精准更新到真正用到该值的组件

另一方面请注意,context值改变时,所有消费了该context的组件都会rerender,

使用社区提供的use-context-selector能暂时解决这个问题,

使用react18 的 useSyncExternalStore 或者 zustand 可以 完美解决这个问题。

如何优雅的使用 React Context

每个状态单一职责,拆分更小粒度,不要一个大对象放各种值

某些情况可以使用 display:none 代替 if

升级React18

设置唯一Key且不能为索引

设置为索引其实和没设置是一样的,react默认就是把索引设置为key,

这样设置就相当于是从前往后一一比对,key相同,就会进入内容的对比,

此时如果内容不同,就会更新渲染,key没起到其应该起到的快速对比,复用dom的作用。

封装请求层面的缓存 (key为请求参数 过期时间 实时获取标记)


首屏优化

空闲时间加载与主页面渲染相关的资源

HTML标签

async 一些插件,埋点,用户调研,字体包
<script> html文件的解析,会等待 script 的 加载及执行
<script async> 会异步加载脚本,加载完时会停止html解析,执行script
<script defer> 会异步加载脚本,加载完时会等待html解析结束,执行script

async 执行顺序不确定 defer 执行顺序

<link/script rel='preload'> 在浏览器渲染前 获取css字体等
<link rel='prefetch'> 空闲时间加载 图片视频等

https://juejin.cn/post/7306786497712537650?searchId=202404242116183A016FC0387413B8147B

webpack优化

测试性能的手段

组件渲染次数计算hooks
浏览器LCP(Largest Contentful Paint), 浏览器呈现最大内容元素所需的时间
useWhyDidYouUpdate

性能优化

async 一些插件,埋点,用户调研,字体包
<script> html文件的解析,会等待 script 的 加载及执行
<script async> 会异步加载脚本,加载完时会停止html解析,执行script
<script defer> 会异步加载脚本,加载完时会等待html解析结束,执行script

async 执行顺序不确定 defer 执行顺序

<link/script rel='preload'> 在浏览器渲染前 获取css字体等
<link rel='prefetch'> 空闲时间加载 图片视频等

https://juejin.cn/post/7306786497712537650?searchId=202404242116183A016FC0387413B8147B

keep-alive