React 性能优化
「性能优化」的核心应当是「不订阅视图无关的数据,以避免重复渲染」
而不是「订阅了视图无关的数据,用 useCallback/useMemo 来缓解性能问题」
——苏晗若
说 React 性能优化,其实是想让页面更快加载出来,更流畅。他的本质是减少渲染真实 DOM 节点的频率,减少虚拟 DOM 对比的频率
在 Fiber 一文中,我们讲过 React Fiber 的工作流,简单来说,它分为两个阶段:render 和 commit
Reconciler(协调器)工作的阶段被称为 render 阶段,Renderer(渲染器)工作的阶段被称为 commit 阶段
render 阶段会进行多次的调用(会被高优先级的任务打断,重新调用)
commit 阶段会执行一次调用(虚拟DOM 渲染到真实DOM上)
所以我们就要对着两个阶段进行优化, render 阶段的优化就是减少不变要的更新
触发更新的方式有:forceUpdate、State更新、父组件 Render 触发子组件 Render
commit 阶段是将虚拟DOM渲染到真实DOM上,所以我们需要在这阶段更新 state
简而言之,我们可以把优化方案分为三类
- render 阶段优化。即跳过不必要的组件的渲染更新
- commit 阶段优化。即减少 commit 阶段耗时
- 非渲染方面的优化
render 阶段优化,即跳过不必要的组件更新
PureComponent、React.memo
如果只有父组件发生状态更新,即使父组件传给子组件的所有 Props 都没有修改,也会引起子组件的 Render 过程。PureComponent 和 React.memo 就是应对这种场景的
PureComponent 是对类组件的 Props 和 State 进行浅比较
React.memo 是对函数组件的 Props 进行浅比较
浅比较:只会比较 props 对象的第一层属性,不会深入比较嵌套对象或数组的内部结构
useMemo、useCallback 实现稳定的 Props 值
如果传给子组件的派生状态或函数,每次都是新的引用,那么 PureComponent 和 React.memo 优化就会失效。所以需要使用 useMemo 和 useCallback 来生成稳定值,并结合 PureComponent 或 React.memo 避免子组件重新 Render
useMemo 缓存(复杂)值
useCallback 缓存函数
列表项使用 key 属性
为了 diff 算法能对比,需要给列表项中的每个值加上 key 属性
shouldComponentUpdate
只适用于 class 组件,已经淘汰
commit 阶段优化
这类优化的目的是减少提交阶段耗时,该分类中仅有一条优化技巧
避免在 didMount、didUpdate 中更新组件 State
React 提交阶段的第二步是执行 commit 阶段钩子,它的执行会阻塞浏览器更新页面。如果在提交阶段钩子函数更新组件 State,会再次触发组件的更新流程,造成两倍耗时
非渲染方面的优化
组件按需挂载
可分为懒加载、懒渲染和虚拟列表三类
懒加载
懒加载的实现是通过 Webpack 的动态导入和 React.lazy
方法
懒渲染
当组件进入或即将进入可视区域时才渲染组件。常见的组件 Modal/Drawer 等,当 visible 属性为 true 时才渲染组件内容,也可以认为是懒渲染的一种实现
虚拟列表
虚拟列表是懒渲染的一种特殊场景,不渲染所有的数据,只渲染可视区域中的数据。当用户滑动时,通过监听 scroll 来判断是上滑还是下拉,从而更新数据。同理 IntersectionObserver(交叉观察者) 和 getBoundingClientRect 都能实现
IntersectionObserver:监听一个目标与它祖先元素或顶级文档视窗的交叉状态
getBoundingClientRect :返回元素的大小及其相对视图的位置
参考资料
- React 性能优化 | 包括原理、技巧、Demo、工具使用
- 浅谈 React 性能优化的方向
- 记忆化技术 memoize-one
- 「框架篇」React 中 的 9 种优化技术
- React 高效渲染策略
- 如何全方位优化你的超大型 React 应用 【原创精读】
- 干货:深入了解 React 渲染原理及性能优化
- 可能你的 react 函数组件从来没有优化过
- React 函数式组件性能优化指南
- 打造高性能的 React 应用的几种方式总结
- 「react 进阶」react 开发者的不得不知道的八条优化建议
- 这可能是全网最全的 react 性能优化知识锦集
- 从源码中来,到业务中去,React 性能优化终极指南
- React Performance Optimization Tips
- 新版 react 中,usecallback 和 usememo 是不是值得大量使用?
- React 性能优化 | 包括原理、技巧、Demo、工具使用