React 虚拟DOM diff算法

虚拟DOM
virtul DOM 也就是虚拟节点,通过JS的Object对象模拟DOM中的真实节点对象,再通过特定的render方法将其渲染成真实的DOM节点

平常我们想到的做法是:
1.state数据
2.JSX模板
3.数据 + 模板结合,生成真实的DOM,来显示
4.state发生改变
5.数据 + 模板结合,生成真实的DOM,替换原始的DOM
缺陷:
第一次生成了一个完整的DOM片段
第二次生成了一个完整的DOM片段
第二次的DOM替换第一次的DOM
三步操作都非常消耗性能

  • 之后来做一个简单的优化:我们应该只替换更新了的部分,而不应该一股脑地替换

    1.state数据
    2.JSX模板
    3.数据 + 模板结合,生成真实的DOM来显示
    4.state发生改变
    5.数据 + 模板结合,生成真实的DOM,并不是直接替换原始的DOM
    6.新的DOM(实际上就是DocumentFragment),和原始的DOM作对比,找差异
    7.找出input框发生的变化
    8.只用新的DOM中的input元素替换,替换掉老的DOM中的input元素
    缺陷:性能的提升并不明显

    • 用虚拟DOM
      1.state数据
      2.JSX模板
      3.数据 + 模板相结合,生成虚拟DOM(虚拟DOM就是一个对象,用来描述真实的DOM),比如:
['div', {id: 'abc'}, ['span', {}, 'hello']]  // 损耗了极小的性能

4.用虚拟DOM的结构生成真实的DOM

<div id = 'abc'><span>hello</span></div>

5.state发生变化
6.数据 + 模板 生成新的虚拟DOM(极大地提升了性能)

['div', {id: 'abc'}, ['span', {}, 'bye']]

·7. 比较原始虚拟DOM新的虚拟DOM的区别,找到区别是span中的内容(极大地提升了性能)
·8. 直接操作DOM,改变span中得内容

优点:

1.性能提升了
2.它使得跨端应用得以实现,由此产生React Native。因为原生应用中是没有DOM这个概念的,不过虚拟DOM的js对象可以被正常识别,因此只要加一层判断辨别是浏览器还是原生app即可将虚拟DOM的思想引入从而使react可以开发原生app

那么,react是在哪里创建虚拟dom的呢?
每次react中的state或者props改变时会触发组件中的render函数,父组件触发render函数时子组件也会跟着触发render函数,而虚拟DOM 即是在render函数中被创建。比如:

render() {
  return <div id='abc'><span>hello</span></div>
}

上图中return的内容是JSX模版,实际上底层实现是用 React.createElement 创建,其接收三个参数,第一个是创建的标签,第二个是它的属性,第三个是它的内容

render() {
  return React.createElement('div', {id: 'abc'}, React.createElement('span', {}, 'hello'))
}

上面两段代码是等价的,JSX模版其实只是react为了让我们开发更简单便捷,其底层还是用 React.creatElement 这个api构建的,即
JSX -> createElement -> 虚拟DOM(js对象) -> 真实DOM

虚拟DOM中的diff算法

用虚拟DOM完成的数据驱动涉及到关键的一点就是我们如何比较两个虚拟DOM的差异。
首先我得确定发生差异的由来,归根结底是组件的state发生了变化,调用了setState方法,之后我们就会生成新的虚拟DOM与旧的进行比对
1.同级比较
在这里插入图片描述
diff算法中只会比较同层级的元素,一旦发现某一级之间有所不同,则会弃置其子级,直接用从新的差异的一级以及其下的所有子级替换老的。我们会有个疑问,这样做那子级中相同的元素不是无法复用了吗,那怎么还能提高比对性能?这无疑是一种缺陷,但也带来了好处就是算法实现简单,也就提高了比对速度,因此最后也是提升了性能的
2.引用key值
for循环中如果没有给每个item所在标签增加一个key值,vue和react中都会发出警告,建议我们加上key值,这是因为当进行虚拟DOM比对时,我们需要比较出相同的元素和不同的,没有key,我们就很难一对应,需要做两层循环比较,用上了key值则我们可以清除比较出那一个新增或删除了什么,就像下图
在这里插入图片描述
有了key值我们就可以轻易判别z是新加的元素从而找出了差异。有一个注意点就是开发中不要用index做key值,这是不建议的。就像下图
在这里插入图片描述
key值问题
如果我们创建了a、b、c三个item,key值分别定义为其index:0、1、2
当我们删除了a,则b、ckey值变为了0、1,则每一项之间无法根据key值一一对应起来了,失去了key值存在的意义。因此建议是用稳定的值作为key值,比如特有的id

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值