虚拟DOM
React原理
我们来想一下如何实现React
第一种方案:
1. state 数据
2. JSX 模板
3. 数据 + 模板 结合, 生成真实的DOM, 来显示
4. state 发生改变
5. 数据 + 模板 结合, 生成真实的DOM, 替换原始的DOM
但这种方案在第五步有着很大的性能缺陷
用新生成的DOM去替换原始的DOM, 非常消耗性能
第二种方案
1. state 数据
2. JSX 模板
3. 数据 + 模板 结合, 生成真实的DOM, 来显示
4. state 发生改变
5. 数据 + 模板 结合, 生成真实的DOM, 并不直接替换原始的DOM
6. 新的DOM (DocumentFragment) 和原始的DOM 做比对,找差异
7. 找出有差异的DOM元素
8. 将有差异的DOM元素替换掉旧的DOM元素
这种方案同样存在缺陷
关键在于第六步,我们找新DOM和原始DOM的比对找差异过程中,也很消耗性能,性能提升并不明显
第三种方案:虚拟DOM
1. state 数据
2. JSX 模板
3. 生成虚拟DOM(JS对象), 用js对象描述dom信息
{
tag: 'div',
attrs: {id: 'root'},
children: [
{
tag: 'p',
children: ['hello, world']
}
]
}
4. 借助虚拟DOM, 生成真实的DOM, 来显示
<div id='root'><p>hello, world</p></div>
5. state 发生改变
6. 生成新的虚拟DOM
7. 比较原始虚拟DOM和新的虚拟DOM的差异
8. 直接操作DOM,改变有差异的内容
优点:生成 js 对象很快, 所以在两个js对象中找差异 损耗性能很小
极大的提升了性能
diff算法
diff算法用于比较虚拟dom之间的差异
1. 逐级比较
diff算法通过逐级的去比较两颗节点树的差异,大大降低了复杂性
2. 列表List
假设我们有一个组件,它在一个迭代中渲染了5个组件,而下一次渲染的时候在组件列表的中间插入一个新的组件。 只是通过这个信息真的很难知道如何在两个组件列表之间进行映射。
默认情况下,React将先前列表的第一个组件与下一个列表的第一个组件相关联,等等。您可以提供一个Key属性,以帮助React去找到他们的映射关系。 在实际中,这通常很容易把刚刚插入的组件从他们当中找出来。