
React 并不会在每次状态更新时重建整个组件树的虚拟 DOM;它仅重新执行状态变更组件及其子组件的 render 函数,生成局部新虚拟节点,并通过高效 diff 算法比对差异,最终只更新真实 DOM 中真正变化的部分。
react 并不会在每次状态更新时重建整个组件树的虚拟 dom;它仅重新执行**状态变更组件及其子组件**的 render 函数,生成局部新虚拟节点,并通过高效 diff 算法比对差异,最终只更新真实 dom 中真正变化的部分。
React 的渲染机制常被简化为“每次 setState 重建整个虚拟 DOM”,但这是一种常见误解。实际上,React 的更新是自顶向下、逐层收敛、按需触发的精细化过程。
渲染起点:从状态变更组件开始
当某个组件(例如 D)调用 setState 或触发 useState 更新时,React 会将该组件标记为“待更新”。随后,React 从该组件开始,自上而下执行其 render 函数(即函数组件体或类组件的 render() 方法),并递归调用其所有子组件的 render 函数——但仅限于该组件的子树范围内。
以如下组件结构为例:
function A() { return <B />; }
function B() { return <C />; }
function C() { return <D />; }
function D() {
const [count, setCount] = useState(0);
return <div>Count: {count}</div>;
}若仅 D 内部状态更新,React 不会执行 A、B、C 的 render 函数(前提是它们未被显式标记为需更新,如未使用 useEffect 触发父级重渲染,也未接收新 props)。但注意:由于 C 是 D 的直接父组件,而 D 是 C 的返回内容,React 在协调(reconciliation)过程中仍需访问 C 的 render 结果——不过此处 C 是纯函数且无状态/副作用,React 可通过 React.memo 或自动浅比较跳过其重新执行(详见后文)。
更准确地说:
✅ React 一定重新执行:D(状态源)及其所有子组件(如有);
⚠️ React 可能跳过执行:C、B、A —— 若它们是纯函数组件且 props 未变,React 会在协调阶段直接复用上次的 ReactElement 对象,避免不必要计算。
虚拟 DOM 的“生成”本质是 JSX 执行结果
所谓“生成新的虚拟 DOM”,实质是执行组件函数后返回的 React.createElement() 调用链结果(即 ReactElement 对象树)。例如:
// D 组件更新后重新执行:
function D() {
const [count, setCount] = useState(1); // 新值
return React.createElement('div', null, 'Count: ', count);
// → 返回一个新的 ReactElement 对象(与上次不同)
}这个新对象构成 D 子树的局部虚拟 DOM 片段,而非全局树。
Diffing 过程:局部比对,非全量重建
React 的协调器(Reconciler)拿到 D 上次的 ReactElement(旧树片段)和本次新生成的 ReactElement(新树片段)后,执行深度优先、同层比较(same-level only) 的 diff 算法:
- 比较 type(如 'div')、key、props(含 children);
- 若 type 不同(如 div → span),直接卸载旧子树,挂载新子树;
- 若 type 相同,则递归 diff 其 props.children;
- 对列表元素,借助 key 实现移动识别,避免错误复用。
关键点:diff 作用域严格限定在被更新组件的输出子树内,不会跨到兄弟分支(如 C 的另一个子组件 E)或祖先组件。
性能保障:默认优化与主动控制
React 默认提供两层防护避免过度渲染:
- 函数组件 props 浅比较:若父组件(如 C)未改变 props,且自身无状态,React 可跳过其 render(需配合 React.memo 显式声明);
- shouldComponentUpdate / React.memo / useMemo / useCallback:开发者可进一步约束子树更新边界。
示例:防止 C 因父级无关更新而重渲染
const C = React.memo(() => <D />); // 仅当 props 改变时才重新执行
总结:React 渲染的三个核心原则
- 定向触发(Targeted):更新始于状态变更组件,影响范围止于其子树;
- 惰性生成(Lazy):虚拟 DOM 节点仅在 render 执行时按需创建,非全局快照;
- 增量更新(Incremental):diff 基于局部新旧节点对比,DOM 操作最小化。
理解这一点,有助于写出更高效的 React 应用:合理拆分组件、善用 memo、避免在 render 中创建匿名函数或对象——因为这些行为虽不触发全树重绘,却可能破坏子组件的浅比较优化,导致本可跳过的渲染被意外激活。










