react如何diff
React Diff 算法原理
React 的 Diff 算法是虚拟 DOM(Virtual DOM)更新的核心机制,用于高效比较新旧虚拟 DOM 树的差异,并最小化实际 DOM 操作。以下是其核心原理和优化策略:
同级比较(Tree Diff)
React 采用分层比较策略,仅对比同一层级的节点,避免跨层级遍历。如果发现节点类型不同(如从 div 变为 span),直接销毁旧节点及其子树,创建新节点。
组件类型判断
当组件类型相同时,React 会递归比较子节点;类型不同时,直接替换整个组件。这避免了深层递归的性能损耗。
Key 属性优化
列表项通过 key 标识唯一性,帮助 React 识别节点的移动、添加或删除。未提供 key 时,React 默认使用索引,可能导致性能下降或状态错误。
节点更新策略
- 相同类型 DOM 节点:仅更新变化的属性(如
className、style),避免重新创建节点。 - 相同类型组件:保留实例,更新
props并触发生命周期方法(如componentDidUpdate)。
Diff 算法的代码示例
以下是一个简化的 Diff 实现逻辑,展示如何比较新旧节点:
function updateElement(parent, oldNode, newNode, index = 0) {
if (!oldNode && newNode) {
// 新增节点
parent.appendChild(createElement(newNode));
} else if (oldNode && !newNode) {
// 删除节点
parent.removeChild(parent.childNodes[index]);
} else if (isDifferent(oldNode, newNode)) {
// 替换节点
parent.replaceChild(createElement(newNode), parent.childNodes[index]);
} else if (newNode.type) {
// 更新属性和子节点
updateAttributes(parent.childNodes[index], oldNode.props, newNode.props);
const oldChildren = oldNode.children || [];
const newChildren = newNode.children || [];
for (let i = 0; i < Math.max(oldChildren.length, newChildren.length); i++) {
updateElement(
parent.childNodes[index],
oldChildren[i],
newChildren[i],
i
);
}
}
}
性能优化建议
- 避免动态
key:如使用随机数或索引可能导致不必要的重建。 - 减少顶层节点变化:频繁替换顶层组件会触发整树卸载。
- 使用
React.memo或shouldComponentUpdate:避免不必要的子组件 Diff。
通过这种策略,React 确保在 O(n) 时间复杂度内完成差异比较,显著提升渲染效率。







