返回

React setState 深度解析:解读源码,透视渲染机制

前端

引子

React 中的 setState 函数,看似简单,却暗藏玄机。它的运作机制往往令人费解,特别是它的异步更新行为,经常让人丈二和尚摸不着头脑。本文将深入 React setState 源码,逐行剖析其内部实现,揭开它的神秘面纱。

setState 初探

setState 函数负责更新组件状态。它接受一个更新对象作为参数,合并到组件的当前状态中。乍一看,这似乎是个简单的过程,但实际上,它涉及到一连串复杂的异步操作。

源码剖析

要了解 setState 的运作机制,我们必须深入其源码。在 React 18 版本中,setState 函数位于 react-dom/cjs/react-dom.development.js 文件中,具体实现如下:

export function setState(inst, payload, callback) {
  const partialState = typeof payload === 'function' ? payload(inst.state) : payload;
  const prevState = inst.state || {};
  const state = Object.assign({}, prevState, partialState);
  inst.state = state;
  // ... 省略其他代码
}

异步更新流程

从源码中可以看出,setState 并没有立即更新组件状态,而是将其存储在实例的 state 属性中,并触发一个异步更新流程。这个流程包含以下步骤:

  1. 调度更新: setState 调用会调度一个更新任务,将其添加到 React 的更新队列中。
  2. 批量更新: React 会将多个更新任务批量处理,以提高效率。在批量更新阶段,React 会遍历更新队列,并调用各个组件的 shouldComponentUpdate 方法。
  3. 状态更新: 如果 shouldComponentUpdate 返回 true,React 会调用组件的 render 方法,更新组件的虚拟 DOM。
  4. DOM 更新: React 会将更新后的虚拟 DOM 与上一次渲染的虚拟 DOM 进行对比,生成差异更新。然后,它会将差异更新应用到实际的 DOM,完成视图更新。

4 次 log 的解析

基于上述的异步更新流程,我们可以理解为什么 setState 调用会产生 4 次 log。这 4 次 log 对应着以下 4 个阶段:

  1. 第一次 log: setState 调用时,更新任务被调度,此时 log 为 0。
  2. 第二次 log: 批量更新阶段,组件的 shouldComponentUpdate 返回 true,log 为 0。
  3. 第三次 log: 组件的 render 方法被调用,此时状态已更新,log 为 2。
  4. 第四次 log: DOM 更新阶段,实际的 DOM 被更新,此时 log 为 3。

总结

React setState 函数的异步更新行为旨在优化性能,防止不必要的重新渲染。通过深入理解 setState 的源码和更新流程,开发者可以更好地优化组件性能,构建更高效的 React 应用。