性能优化
-
什么是性能优化 命中「性能优化」的组件可以不通过 reconcile 生成 wip.child,而是直接复用上次更新生成的 wip.child。
-
React 中性能优化的策略有哪些
- bailout 策略
如果
状态没有改变则复用上次更新生成的 wip.child。 - eagerState 策略 计算更新后的状态,如果与跟新前的状态相同,这不会开启后续的调度流程,所以也不会再有 render
- bailout 策略
如果
-
什么时候才会命中性能优化 什么才会导致组件的变化 我们根据
UI=f(state)我们可以知道UI的变化是与状态有关而状态来源有哪些呢,也就是变化的部分- state
- props
- context
-
性能优化思路
- 将「变化的部分」与「不变的部分」分离。
- 命中性能优化的组件的子组件(而不是他本身)不需要 render。 未优化的情况
import { useEffect, useRef, useState } from "react"; import "./App.css"; function BigComp() { let newData = performance.now(); while (performance.now() - newData < 2000) {} console.log("子组件 render"); return <p>大组件</p>; } function App() { const [num, setNum] = useState(0); console.log("父组件 render"); return ( <div> <p>{num}</p> <button onClick={() => { console.log("click"); setNum((num) => num + 1); }} > 加一 </button> <BigComp /> </div> ); } export default App;从代码中有两个组件一个父组件 组件, 还有一个耗时 2 秒的任务的子组件 。我们不尽进行任何的性能优化时我们可以看到每次点击
加一按钮就会有卡顿现象{num}没有及时更新在页面上。因为有占用主线程执行一些耗时任务。那我们需要进行组件的优化-
将「变化的部分」与「不变的部分」分离。
-
情况一
import { useEffect, useRef, useState } from "react"; import "./App.css"; function BigComp() { let newData = performance.now(); while (performance.now() - newData < 2000) {} console.log("子组件render"); return <p>大组件</p>; } function Num({ children }) { const [num, setNum] = useState(0); return ( <> <p>{num}</p> <button onClick={() => { console.log("click"); setNum((num) => num + 1); }} > 加一 </button> </> ); } function App() { return ( <div> <Num /> <BigComp /> </div> ); } export default App;从代码中有三个组件一个父组件 组件,还有一个, 还有一个耗时 2 秒的任务的子组件 。我们将变化的组件与不变的组件进行分离,我们可以看到每次点击
加一,按钮就不会有{num}的卡顿现象,也不再打印出子组件render。说明我们命中了组件的性能优化并没有重新触发组件的 render; -
情况二
如果我们
num变化需要跟新div节点的data-title的属性值我们要怎么做呢,这样我们就不能将拆解出去,再不使用 React 的性能优化的 hook 我们要怎么解决呢。import { useEffect, useRef, useState } from "react"; import "./App.css"; function BigComp() { let newData = performance.now(); while (performance.now() - newData < 2000) {} console.log("子组件render"); return <p>大组件</p>; } function NumWrapper({ children }) { const [num, setNum] = useState(0); return ( <div data-title={num}> <p>{num}</p> <button onClick={() => { console.log("click"); setNum((num) => num + 1); }} > 加一 </button> {children} </div> ); } function App() { return ( <NumWrapper> <BigComp /> </NumWrapper> ); } export default App;从代码中有三个组件一个父组件 组件,还有一个,他接受一个
children作为他的子组件, 还有一个耗时 2 秒的任务的子组件 。我们在组件中将 是将组件 放在组件中,将作为 children 传递给 ,我们可以看到每次点击加一按钮,也不会有{num}的卡顿现象,也不再打印出子组件render。说明我们命中了组件的性能优化并没有重新触发组件的 render; 为什么会出现这种情况,为什么和我们不优化时的情况不一样呢,其实这个情况是因为我们将 作为 props 传递到中,当组件重新 render 时 的渲染不在 中定义 所以不会触发的重新 render
-
总结 一般在我们项目开发中遇到组件的性能瓶颈时,我们可以找到耗费性能的组件的父组件使用 将「变化的部分」与「不变的部分」分离,使其能够命中 react 的性能优化,减少 render。
版权声明:本系列文章是基于 《从 0 实现 React18》 整理创作的,视频教程的作者是 @卡颂 。