
教程前端文档【免费下载链接】Under-the-hood-ReactJSEntire React code base explanation by visual block schemes (Stack version)项目地址https://gitcode.com/gh_mirrors/un/Under-the-hood-ReactJS点击查看免费下载本篇文章基于本仓库stack/languages/korean/book/Part-14.md韩文版及其英文原版stack/book/Part-14.md展开。它是《Under the hood ReactJS》Stack reconciler 系列图解书共 15 个部分的最后一环完整承接 Part 10Part 13 的更新调用链ReactUpdates.runBatchedUpdates → ReactReconciler.performUpdateIfNecessary → updateComponent → _updateDOMProperties → _updateDOMChildren。读完本文你将掌握setState触发更新后React 如何递归协调 children、如何生成更新配置对象如TEXT_CONTENT最终由DOMChildrenOperations.processUpdates驱动真实 DOM 的文本替换以及componentDidUpdate如何通过事务包装器被延迟调用。这是理解 React Stack 版本更新updating全流程收官的实战级指南。Part 14 在整个更新流程中的位置在进入 Part 14 之前先快速回顾此前各章建立的调用链以便理解这最后一块拼图承接的是什么Part 10setState后组件被标记为 dirtyReactUpdates.runBatchedUpdates按mount order排序 dirty components并通过ReactUpdatesFlushTransaction事务执行批量更新详见 Part 10。Part 11ReactCompositeComponent.updateComponent处理 props 变化、合并nextState、调用componentWillReceiveProps与shouldComponentUpdate详见 Part 11。Part 12若组件确实需要更新先调用componentWillUpdate再执行render并用shouldUpdateReactComponent判断是局部更新还是整体替换详见 Part 12。Part 13ReactReconciler.receiveComponent将 next element 传给ReactDOMComponent其updateComponent执行两大动作——_updateDOMProperties处理属性、样式、事件监听与_updateDOMChildren处理子节点内容源码路径标注为src\renderers\dom\shared\ReactDOMComponent.js#1076详见 Part 13。Part 14 讲解的正是_updateDOMChildren的内部实现它如何协调reconcile子节点把 children 递归拆解到最底层的内容content级别并用一个更新配置对象描述将要执行的 DOM 操作。children 协调的本质两种分支一套递归文档开门见山地指出该方法使用影响子节点内容的各种属性来协调 children。虽然表面上有若干种可能场景但技术上只有两种主要情况complex复杂children 仍然是 React 组件React 需要逐层递归直到最终抵达内容层simple简单children 是字符串或数字等简单类型即已经是内容content本身。分支的开关是nextProps.children的类型图中标注为 (1)。在本系列全程使用的示例中ExampleApplication组件恰好包含三个 childrenrender() { return div button onClick{this.onClickHandler.bind(this)}set state button/button ChildCmp childMessage{this.state.message} / And some text as well! /div }即buttonDOM 元素、ChildCmp自定义组件、text string文本内容三种形态正好覆盖了两种分支路径。完整示例代码含全部生命周期钩子见本系列 Intro 的代码示例。文档强调这是 Reactv15.4.2Stack reconciler时代的行为children类型分支与后续 Fiber 版本存在差异阅读时需注意版本前提。第一轮迭代complex children 的逐一遍历处理ExampleApplication的 children 是第一轮迭代。显然button、ChildCmp都不是内容类型因此进入complex 分支取出所有 children逐一走一遍此前为父组件构建的几乎相同的过程即更新/挂载的完整判定流程。文档特别提醒一个容易造成误解的校验块——shouldUpdateReactComponent图中标注为 (2)。它表面上像在检查是否需要更新但实际判定的是更新update还是 删除重建delete create。在示意图中为保持简洁省略了 NO 分支即判定为删除重建的路径但其完整判定逻辑在 Part 12 中有完整代码function shouldUpdateReactComponent(prevElement, nextElement) { var prevEmpty prevElement null || prevElement false; var nextEmpty nextElement null || nextElement false; if (prevEmpty || nextEmpty) { return prevEmpty nextEmpty; } var prevType typeof prevElement; var nextType typeof nextElement; if (prevType string || prevType number) { return (nextType string || nextType number); } else { return ( nextType object prevElement.type nextElement.type prevElement.key nextElement.key ); } }也就是说当新元素为null/false被 render 逻辑移除、类型变化如div变成其他标签或 key 不一致时组件会被整体卸载并重建只有类型、key 不变时才走局部更新路径。此外React 还会比较旧 children 与当前 children如果某个 child 被移除则先unmountComponent再将其从 DOM 中删除。children 更新clickable可点击在新标签页打开并放大查看建议与正文分窗口对照阅读。第二轮迭代button 的文本比较 —— VirtualDOM 思想的现场演示第二轮迭代处理button这是简单分支的典型代表。button的 children 只是字符串set state button类型是纯文本text。React 检查上一次的文本与当前是否相同——由于文本并未改变因此无需更新button对应的 DOM 节点。文档在此点破了常被抽象化的 VirtualDOM 概念React 维护 DOM 的内部表示虚拟表示只在确有必要时才触碰真实 DOM。这正是其性能出色的根本原因之一——更新路径上每多一次无变化的比较并跳过就少一次真实的 DOM 写入。ChildCmp 递归到底层content 真的被修改随后ChildCmp进入更新队列。React 对其子节点继续递归直到抵达最低层级的条目content并更新它。这里值得注意该 content 确实会被修改。回顾 Intro 的示例代码与 Part 14 中展示的代码片段//... onClickHandler() { this.setState({ message: click state message }); } render() { return div button onClick{this.onClickHandler.bind(this)}set state button/button ChildCmp childMessage{this.state.message} / //...用户在页面点击按钮触发onClickHandlersetState({ message: click state message })将 state 更新为click state message。随后ChildCmp通过this.props.message即childMessage读到新值因此它的 content 从旧文本变为click state message——这正是本次更新真正要落地的 DOM 改动。更新配置对象一次更新的操作清单文档接着揭示更新的本质更新其实是一个配置对象会被解析后执行相应的既定动作。以本文的文本更新为例配置对象长这样{ afterNode: null, content: click state message, fromIndex: null, fromNode: null, toIndex: null, type: TEXT_CONTENT }可以观察到该对象几乎为空——文本更新确实非常直观只需告诉 React把父节点下的文本内容替换为click state message。但配置对象里依然存在大量字段如afterNode、fromIndex、fromNode、toIndex这是因为移动move节点等场景远比单纯替换文本复杂需要记录来源节点、参考锚点与目标索引才能正确地把节点从一个位置挪到另一个位置。type字段则决定了后续processUpdates的 switch 分支走向。源码深挖DOMChildrenOperations.processUpdates 的五种更新类型文档给出了processUpdates的完整源码让配置对象到真实 DOM 操作之间的桥梁一目了然源码路径标注src\renderers\dom\client\utils\DOMChildrenOperations.js#172属于 React v15.4.2processUpdates: function(parentNode, updates) { for (var k 0; k updates.length; k) { var update updates[k]; switch (update.type) { case INSERT_MARKUP: insertLazyTreeChildAt( parentNode, update.content, getNodeAfter(parentNode, update.afterNode) ); break; case MOVE_EXISTING: moveChild( parentNode, update.fromNode, getNodeAfter(parentNode, update.afterNode) ); break; case SET_MARKUP: setInnerHTML( parentNode, update.content ); break; case TEXT_CONTENT: setTextContent( parentNode, update.content ); break; case REMOVE_NODE: removeChild(parentNode, update.fromNode); break; } } }五种更新类型及其底层操作可归纳如下type底层操作作用INSERT_MARKUPinsertLazyTreeChildAt将新内容插入到afterNode之后惰性子树方式MOVE_EXISTINGmoveChild将fromNode移动到afterNode之后实现节点移位SET_MARKUPsetInnerHTML直接设置父节点内部 HTML适用于整段标记替换TEXT_CONTENTsetTextContent设置父节点的文本内容REMOVE_NODEremoveChild从父节点移除fromNode对应 children 被删除的场景getNodeAfter(parentNode, update.afterNode)用于计算插入/移动时的参考锚点afterNode为null时通常意味着插到开头。这正是上一节提到的afterNode字段在配置对象中的实际用途。setTextContent真正改写真实 DOM 的最后一击在本文场景中update.type是TEXT_CONTENT因此 switch 进入最后一个关键步骤调用setTextContent(parentNode, update.content)图中标注为 (3)直接修改真实 HTML 节点DOM 中实际存在的节点的文本内容。至此一次文本更新的虚拟层 → 真实层传递完成setState改的是 JavaScript 内存中的 state →render产出新的 element → 协调器比较并生成TEXT_CONTENT更新配置 →processUpdates根据配置调用setTextContent→ 浏览器中的页面为用户重新渲染出click state message。componentDidUpdate 的延迟回调事务包装器与 callbackQueue.notifyAll内容已更新、页面已重渲染更新流程还剩最后一件事调用组件钩子componentDidUpdate。文档指出其调用机制正是系列反复出现的transaction事务包装器dirty 组件的更新此前被ReactUpdatesFlushTransaction事务包装详见 Part 10该事务的某个 wrapper 内部包含this.callbackQueue.notifyAll()逻辑正是这段逻辑在事务close阶段批量触发所有被延迟postpone的回调从而调用componentDidUpdate。这解释了为什么componentDidUpdate总在更新收尾阶段才执行——它在setState时只是被入队延后真正被 notify 是在ReactUpdatesFlushTransaction事务完成时。这一设计让所有生命周期回调的执行顺序保持一致避免在更新中途被嵌套地过早调用。收官Part 14 的核心价值与 updating 全貌Part 14 的完整示意图part-14.svg描绘了_updateDOMChildren协调子节点的全过程去除次要分支后得到简化图part-14-A.svg再修正排版后为重构版part-14-B.svg。从这些示意图中抽取的核心价值part-14-C.svg最终汇入整个更新流程的总览图Part 14clickablechildren 协调全流程。UpdatingclickableStack reconciler 更新updating全流程收官总览。Part 14 的实质内容可以一句话概括_updateDOMChildren按nextProps.children的类型分叉——复杂类型递归协调简单类型文本/数字直接比较内容需要变动时生成描述性更新配置对象交给DOMChildrenOperations.processUpdates以TEXT_CONTENT或INSERT_MARKUP、MOVE_EXISTING、SET_MARKUP、REMOVE_NODE方式作用于真实 DOM最后由ReactUpdatesFlushTransaction事务触发componentDidUpdate。这就是 Stack reconciler 从setState到页面刷新的完整闭环的最后一环。延伸阅读韩文版系列入口韩文 README本部分韩文原档Part 14韩文更新链路前序章节Part 10dirty components 与事务、Part 11updateComponent 与生命周期、Part 12shouldUpdateReactComponent 与 render、Part 13receiveComponent 与_updateDOMProperties全系列总览与调试示例代码Intro、README赞分享教程前端文档【免费下载链接】Under-the-hood-ReactJSEntire React code base explanation by visual block schemes (Stack version)项目地址https://gitcode.com/gh_mirrors/un/Under-the-hood-ReactJS点击查看免费下载相关推荐Under-the-hood ReactJS子组件 children 更新的完整流程Stack 协调器 Part 14Under the hood ReactJS子组件 children 更新的完整流程Stack 协调器 Part 14 导读 这是 React Stac教程前端文档Under-the-hood ReactJSStack 版源码解析 Part 14子组件更新、TEXT_CONTENT 文本替换与 componentDidUpdate 收尾Under the hood ReactJSStack 版源码解析 Part 14子组件更新、TEXT_CONTENT 文本替换与 componentDi教程前端文档Under-the-hood-ReactJS 源码解读 Part 13Stack 协调器更新链路中 ReactDOMComponent 的 receiveComponent 与 DOM 子节点更新Under the hood ReactJS 源码解读 Part 13Stack 协调器更新链路中 ReactDOMComponent 的 receiveCo教程前端文档上一篇Nigate3分钟免费搞定Mac读写NTFS指南下一篇EdgeRemover 完整指南三步彻底卸载 Microsoft Edge支持一键装回创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考