- 教程
- 前端
- 文档
【免费下载链接】Under-the-hood-ReactJS
Entire React code base explanation by visual block schemes (Stack version)
本文基于 stack/languages/korean/book/Part-11.md(Part 11「Update component」)展开,对应英文原文 stack/book/Part-11.md。本篇聚焦 Stack reconciler 更新流程中最核心的
ReactCompositeComponent.updateComponent方法:它是setState与 props 变更汇合后的「决策中枢」,决定了componentWillReceiveProps、shouldComponentUpdate、forceUpdate等生命周期语义如何落地,以及 React 如何基于pending state queue重新计算nextState并决定是否真正执行 DOM 更新。读完本篇,你将完整掌握 React v15.4.2(Stack 版本)中一个已挂载组件被更新时,从「props 是否变化」到「是否允许更新」的完整决策链,并能把它接入整个 updating 大流程(Part 8 → Part 10 → Part 11 → Part 12)进行整体理解。
一、updateComponent 在更新流程中的位置
在进入updateComponent之前,先回顾它是如何被触发的。正如 Part 10(Dirty components) 所示,React 更新从ReactUpdates.runBatchedUpdates开始,逐个遍历dirtyComponents数组,将每个 dirty 组件交给ReactReconciler.performUpdateIfNecessary,最终调用到ReactCompositeComponent实例上的updateComponent方法(对应图 11.0 左上角的入口节点)。
这一调用链与setState的源头在 Part 8 中已经拆解:enqueueSetState先把this.setState传入的 partial state 推入内部实例的_pendingStateQueue,随后enqueueUpdate把组件推进dirtyComponents列表。也就是说,一个 dirty 组件在批处理中被取出后,最终都会落到updateComponent里做统一的更新决策。
代码中对updateComponent方法职责的原始注释给出了官方定位:
“Perform an update to a mounted component. The componentWillReceiveProps and shouldComponentUpdate methods are called, then (assuming the update isn't skipped) the remaining update lifecycle methods are called and the DOM representation is updated. By default, this implements React's rendering and reconciliation algorithm. Sophisticated clients may wish to override this.”
翻译过来即:对已挂载组件执行更新。componentWillReceiveProps与shouldComponentUpdate会被调用;随后(假设更新未被跳过)其余更新生命周期方法会被调用,DOM 表示被刷新。默认情况下该方法实现了 React 的渲染与协调(reconciliation)算法,复杂客户端可能希望重写它。
说明:本仓库是「图解 React 内部实现」的知识库,不包含 React 源码本体;文中涉及的具体源码路径与行号均来自系列文档中对 v15.4.2 代码的引用记录,例如
src/renderers/shared/stack/reconciler/ReactUpdates.js#125(见 Part 10)。
二、第一步:检查 props 是否真的发生了变化
updateComponent的开场动作,是判断props(图 11.0 中的节点 01)是否被修改。技术上,updateComponent可能由两种场景触发:
- 调用了
setState:组件自身状态变更引发的更新; - props 发生了变化:父组件重新渲染导致传入的 props 更新。
如果在_currentElement与传入的nextParentElement之间比较发现 props 确实变化了,React 就会调用生命周期方法componentWillReceiveProps(nextProps, nextContext)(图 11.0 右上角节点)。这也是该方法名「Receive Props」的来源——它在组件即将接收一组新 props 时被调用,是组件响应父级变更、执行派生逻辑(如重置局部状态、准备数据请求)的标准时机。
三、第二步:基于 pending state queue 重新计算 nextState
无论 props 是否变化,React 接下来都要重新计算组件的下一个状态nextState,计算依据是内部实例上的pending state queue(待处理状态队列)——也就是 Part 8 中enqueueSetState依次 push 进去的 partial state 对象队列。
在本文的调试场景里,队列内容形如:
[{ message: "click state message" }]这正是 Intro 代码示例 中onClickHandler里被注释掉的this.setState({ message: 'click state message' })所入队的 partial state。图 11.0 中对应的计算节点为nextState = this._processPendingState(nextProps, nextContext),其内部核心操作可以概括为逐条将 partial state 合并:
nextState = Object.assign({}, partial) // 依次合并队列中的每个 partial state需要注意的是:如果本次更新只是 props 变化(而非 setState 触发),state 保持不变,nextState直接沿用当前this.state。这正是 React「state 归组件自己管、props 归父级管」职责划分的体现。
四、第三步:shouldUpdate 的默认值为何是 true
计算完nextState后,React 进入更新裁决阶段。它先把局部变量shouldUpdate赋值为默认值true(图 11.0 节点 03):
shouldUpdate = true这从机制上解释了 React 的一个重要默认行为:即使组件没有显式声明shouldComponentUpdate,组件默认也会被更新。换言之,「每次 setState / props 变更都触发重新渲染」是 Stack 版本 React 的默认策略,而shouldComponentUpdate是开发者用来关闭这条默认路径的优化开关。
五、第四步:force update 检查与 shouldComponentUpdate 裁决
接着,React 检查这次更新是否为强制更新(force update)(图 11.0 中的菱形判断!_pendingForceUpdate):
- 若是 force update:说明组件是被
forceUpdate()强制要求刷新的,shouldComponentUpdate会被跳过(即使显式声明了也不会被调用),组件无条件进入更新流程; - 若不是:React 会调用组件上显式声明的
shouldComponentUpdate(nextProps, nextState, nextContext)方法,并将其返回值重新赋给shouldUpdate。
关于forceUpdate,React 官方文档明确表示它是一个应尽量避免使用的坏实践(bad practice)——因为绕过shouldComponentUpdate意味着放弃了 React 提供的性能保护机制,也绕开了「数据变更驱动渲染」的声明式心智模型。正常场景下应当通过修改state或props来触发更新。
Intro 示例中的ExampleApplication恰好声明了:
shouldComponentUpdate(nextProps, nextState, nextContext) { return true; }因此在常规更新路径中,它的返回值会驱动shouldUpdate的最终结果。
六、短路机制:shouldUpdate 为 false 时 React 仍然要做什么
shouldUpdate为false时,_performComponentUpdate(真正执行componentWillUpdate→render→ DOM 更新的阶段,详见 Part 12)会被跳过——这是 React 避免冗余 DOM 操作、保证性能的核心手段之一。
但这里有一个容易忽略的细节:即使判定组件不需要更新,React 仍然需要同步props与state。从图 11.0 下半部分的流程可以看到,即便走了「No」分支,React 依旧执行:
this._currentElement = nextParentElement; // 同步最新的元素 inst.props = nextProps; // 同步最新的 props inst.state = nextState; // 同步最新的 state这样做的目的很直白:把外部可见的实例数据(props、state)先对齐到最新值,后续若仍有更新发生,剩余流程可以更快地执行(无需再重复计算nextState、比对 props),相当于为后续更新做了一次「预热」。这也回应了 Part 11 原文中「React 依然要设置 props 和 state,但会跳过其余更新」的表述。
七、图解回顾:从完整流程到核心要点
Part 11 的图解在原文中经过了三层提炼:
- 完整流程(11.0):
updateComponent入口 → props 变化判断 →componentWillReceiveProps→_processPendingState计算nextState→shouldUpdate = true→ force update 判断 →shouldComponentUpdate裁决 → 更新短路或进入_performComponentUpdate→ 同步_currentElement/inst.props/inst.state。
- 简化版(11.1):去掉次要细节,保留主干判断节点;
- 重构版(11.2):修正布局与对齐,把判断与执行节点归置清晰。
最终提炼出的核心骨架(11.3)被直接纳入整个 updating 总图,作为组件更新「裁决阶段」的标准表达。至此,一个 dirty 组件从dirtyComponents队列中被取出,经过updateComponent的 props 检查、nextState 计算与 shouldUpdate 裁决之后,要么被短路,要么带着最终确定的nextProps、nextState、nextContext进入_performComponentUpdate—— 而这正是 Part 12「If components actually should update..」 接下来要展开的内容(componentWillUpdate、重新调用render、componentDidUpdate的延迟入队等)。
八、小结:Part 11 的可复用结论
| 环节 | 行为 | 关键影响 |
|---|---|---|
| props 变化检测 | prevParentElement !== nextParentElement则调用componentWillReceiveProps(nextProps, nextContext) | 组件响应父级 props 变更的入口 |
| nextState 计算 | _processPendingState(nextProps, nextContext),逐条合并_pendingStateQueue中的 partial state | 纯 props 更新时 state 保持不变 |
| 默认更新策略 | shouldUpdate = true | 未声明shouldComponentUpdate时默认更新 |
| force update | !_pendingForceUpdate为 false 时跳过shouldComponentUpdate | forceUpdate会绕过性能保护,官方建议避免使用 |
| shouldComponentUpdate | 返回结果重新赋给shouldUpdate | 自定义更新裁决的唯一标准钩子 |
| 短路行为 | shouldUpdate === false时跳过_performComponentUpdate,但仍同步_currentElement/props/state | 兼顾数据一致性与渲染性能 |
这篇文档与整个系列一样,来自对 React v15.4.2 Stack reconciler 代码的逐行调试与可视化归纳(总览见 Intro 与 stack/languages/korean/book/README.md),覆盖了约六成的核心逻辑。将 Part 11 与 Part 10(dirty 组件批处理)、Part 8(setState 入队)、Part 12(实际执行更新) 串联阅读,即可拼出 Stack 版本 React 组件更新从触发到落地的完整链路。
- 教程
- 前端
- 文档
【免费下载链接】Under-the-hood-ReactJS
Entire React code base explanation by visual block schemes (Stack version)
相关推荐
Brigade 终端聊天TUI指南:14个斜杠命令和实用快捷键全掌握
Brigade 终端聊天TUI指南:14个斜杠命令和实用快捷键全掌握 Brigade 是一款运行在终端的开源个人 AI 智能系统,启动后直接进入一个 终端聊天
教程前端文档基于 agentic-awesome-skills 的 analytics-product 技能实战:从事件埋点到漏斗、Cohort 留存、North Star 与 A/B 检验
基于 agentic awesome skills 的 analytics product 技能实战:从事件埋点到漏斗、Cohort 留存、North Star
教程前端文档React组件树遍历终极指南:深入Under-the-hood-ReactJS架构解析
React组件树遍历终极指南:深入Under the hood ReactJS架构解析 Under the hood ReactJS是一个通过可视化流程图详细解
教程前端文档
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考