← 返回目录

第 6 卷

第 6 / 28 卷日期:

  1. 收集更新请求:加入组件更新队列:
  2. 当调用 setState(partialState) 时,React 首先检查 isBatchingUpdates 标识:若

为 true(处于批量上下文),则不立即处理该更新,而是将 partialState(状态更新描述)加入当前组件的「更新队列」(每个组件实例都有一个独立的更新队列,存储待处理的状态更

新)。

  1. 若 partialState 是函数(如 this.setState(prev => ({ count: prev.count
  • 1 }))),则直接将函数存入更新队列,后续合并时再执行函数计算最终状态(确保依赖前一

个状态的更新能正确叠加)。

  1. 合并更新请求:去重与状态合并:
  2. 同一组件在批量更新上下文中多次调用 setState 时,更新队列会收集所有的

partialState,并在后续合并阶段进行「去重与合并」。

  1. 合并规则:
  2. 若多次更新的是同一个状态字段(如连续两次 setState({ count: 1 })),则仅保留最后

一次更新(去重)。

  1. 若更新的是不同状态字段(如 setState({ count: 1 }) 后调用 setState({ name:

'xxx' })),则合并为一个完整的状态对象(如 { count: 1, name: 'xxx' })。

  1. 若存在函数类型的 partialState,则按顺序执行函数,将前一个函数的返回值作为下一个函

数的参数(确保状态更新的依赖链正确),最终得到合并后的新状态。

  1. 触发批量更新:统一执行渲染流程:
  2. 当批量更新上下文结束( isBatchingUpdates 设为 false)时,React 会触发「批量刷

新」逻辑(通过 flushBatchedUpdates 方法),遍历所有存在待更新队列的组件。

  1. 对于每个组件,取出其更新队列中的合并后的新状态,执行后续的协调(Reconciler)和渲染

(Renderer)流程:对比虚拟 DOM、生成 Diff 补丁、更新真实 DOM,完成一次完整的渲染。

3. React18 自动批处理(Automatic Batching)的扩展实现

React18 之前,批量更新仅支持 React 控制的场景(合成事件、生命周期);React18 通过「自动批处理」扩展了批量更新的范围,其核心实现变化是:

• 将「批量更新上下文」从「全局标识」改为「基于根节点的上下文管理」(通过 createRoot

创建的根节点会维护自己的批量更新状态)。

• 在所有异步场景(原生事件、 setTimeout、 Promise 回调等)中,自动包裹批量更新逻辑,

即进入这些场景时自动开启批量上下文,退出时关闭并刷新更新。

• 若需强制取消批量更新(立即执行更新),可使用 ReactDOM.flushSync 方法,该方法会强制

• 核心价值:减少 DOM 操作次数。若没有批量更新,多次 setState 会触发多次渲染,而批量更

新将多次更新合并为一次渲染,大幅提升性能。

• 注意事项:在批量更新上下文中,无法立即获取 this.state 的最新值(因为状态尚未合并更

新),如需获取最新状态,需使用 setState 的第二个回调参数(如 this.setState({ count: 1 }, () => console.log(this.state.count)))。

十二、React 的生命周期及各阶段方法

React 生命周期是组件从「创建」到「销毁」的完整过程,分为三个核心阶段:挂载阶段(Mounting)、更新阶段(Updating)、卸载阶段(Unmounting)。React16.3 后废弃了部分生

命周期方法(如 componentWillMount),推荐使用更安全的替代方法,具体阶段与方法如下:

1. 挂载阶段(组件从无到有,首次渲染到 DOM)

核心目的:初始化组件状态、绑定事件、请求数据、创建 DOM 节点,执行顺序固定:

1.constructor(props):组件构造函数,最先执行。用于初始化 this.state、绑定事件处理函数(如 this.handleClick = this.handleClick.bind(this)),注意不能在此

处调用 setState(会触发不必要的渲染),也不能调用 this.props(需通过参数 props 访问)。

2.static getDerivedStateFromProps(nextProps, prevState)(React16.3+ 新增,替代 componentWillReceiveProps):静态方法,无 this 指向。用于根据 props 变

化推导状态变化,返回新状态对象(如 return { count: nextProps.count })或 null(不更新状态),适用于「状态完全依赖 props」的场景。

3.render():核心渲染方法,纯函数(无副作用)。返回 JSX 描述 UI 结构,被调用时会生成虚拟 DOM,不直接操作 DOM,可多次调用(如父组件重新渲染时)。

4.componentDidMount():组件挂载完成(DOM 已生成并插入页面)后执行,仅执行一次。常用于:发送网络请求(如获取初始化数据)、绑定原生 DOM 事件(如

addEventListener)、初始化第三方库(如图表库、地图库),此处可安全调用 setState(会触发一次额外渲染,但不会影响首次挂载的性能)。

2. 更新阶段(组件状态/Props 变化,触发重新渲染)

核心目的:处理状态/Props 变化、优化渲染逻辑,执行顺序固定:

1.static getDerivedStateFromProps(nextProps, prevState):与挂载阶段相同,在更新阶段也会执行,用于根据新 Props 推导状态变化。

PureComponent 会自动实现该方法(浅比较 Props/State)。

3.render():重新执行,生成新的虚拟 DOM,与旧虚拟 DOM 对比(Diff 算法)。

4.getSnapshotBeforeUpdate(prevProps, prevState)(React16.3+ 新增,替代 componentWillUpdate):在 DOM 更新前执行,用于捕获 DOM 更新前的快照信息(如滚动

位置、DOM 尺寸),返回的快照值会作为 componentDidUpdate 的第三个参数。适用于需要保存 DOM 状态的场景(如滚动列表更新时保持滚动位置)。

5.componentDidUpdate(prevProps, prevState, snapshot):组件更新完成(DOM 已更新)后执行。常用于:根据 Props/State 变化更新 DOM(如调整第三方库配置)、发送网络

请求(仅当 Props 变化时),此处可调用 setState(但需加条件判断,避免无限循环更新)。

3. 卸载阶段(组件从 DOM 中移除,销毁)

核心目的:清理资源,避免内存泄漏,仅一个方法:

• componentWillUnmount():组件卸载前执行,仅执行一次。常用于:解绑原生 DOM 事件

(如 removeEventListener)、取消网络请求(如中止 fetch 或 axios 请求)、清理定时器(如 clearTimeout)、销毁第三方库实例,此处 setState 不能调用(组件已进入

卸载流程,不会再渲染)。

4. 特殊生命周期方法(错误处理)

React16+ 新增错误边界相关方法,用于捕获子组件渲染错误,避免整个应用崩溃:

• static getDerivedStateFromError(error):静态方法,捕获子组件错误后执行,返

回新状态对象,用于渲染错误提示 UI(如 return { hasError: true })。

• componentDidCatch(error, errorInfo):捕获子组件错误后执行,可用于日志上报

(如将错误信息发送到监控平台), errorInfo 包含错误堆栈信息。

十三、React 生命周期中的性能优化阶段及原理

React 性能优化的核心方向是「减少不必要的重新渲染」,最关键的优化阶段是更新阶段,通过拦截渲染触发流程实现优化;此外,挂载阶段也可通过提前准备数据减少冗余渲染,具体优化点及原理如

下:

1. 核心优化阶段:更新阶段(拦截渲染触发)

更新阶段是组件最常执行的阶段,也是性能优化的重点,核心优化方法是重写

• 优化方法 1:使用 React.PureComponent:

全站分卷索引 · 28 卷
  1. 1第 1 卷
  2. 2第 2 卷
  3. 3第 3 卷
  4. 4第 4 卷
  5. 5第 5 卷
  6. 6第 6 卷
  7. 7第 7 卷
  8. 8第 8 卷
  9. 9第 9 卷
  10. 10第 10 卷
  11. 11第 11 卷
  12. 12第 12 卷
  13. 13第 13 卷
  14. 14第 14 卷
  15. 15第 15 卷
  16. 16第 16 卷
  17. 17第 17 卷
  18. 18第 18 卷
  19. 19第 19 卷
  20. 20第 20 卷
  21. 21第 21 卷
  22. 22第 22 卷
  23. 23第 23 卷
  24. 24第 24 卷
  25. 25第 25 卷
  26. 26第 26 卷
  27. 27第 27 卷
  28. 28第 28 卷