React框架(七)深入理解虚拟dom

参考:https://www.cnblogs.com/cazj/p/10927879.html
https://segmentfault.com/a/1190000015463599

一、React中的核心概念

1、DOM的本质: 浏览器中的概念,用js对象来表示页面上的元素,并提供操作DOM对象的API

2、react中的虚拟DOM:是框架中的概念,是程序员用js对象来模拟页面上的DOM和DOM 的嵌套

3、为什么要实现虚拟DOM:为了实现页面中DOM元素的高效更新

4、DOM和虚拟DOM的区别:

  • DOM:浏览器中提供的概念,用js对象表示页面上的元素,并提供操作议元素的API
  • 虚拟DOM:手动用js对象来模拟DOM元素和嵌套关系

二、脱离React实现虚拟DOM的过程

1. 原始思路

  1. 定义state数据
  2. 定义模板,即对应于React框架中render函数里返回的jsx代码部分
  3. 数据+模板,结合生成真实dom并显示
  4. state改变后
  5. 数据+模板,结合生成真实dom替换原始dom

缺陷:
第一次生成完整dom片段
第二次生成完整dom片段
第二次替换第一次dom
极其损耗性能,因为每次都需要重新渲染整个dom,但事实往往只有一部分dom元素改变

2. 第一次改进

  1. 定义state数据
  2. 定义模板,即对应于React框架中render函数里返回的jsx代码部分
  3. 数据+模板,结合生成真实dom并显示
  4. state改变后
  5. 数据+模板,结合生成真实dom,但不直接替换原始dom
  6. 新旧dom片段做对比,找出差异
  7. 只拿变化的dom替换原始dom

缺陷:
新旧dom片段做对比,找出差异,依旧会损耗性能,性能提升不明显

3. 第二次改进

  1. 定义state数据
  2. 定义模板,即对应于React框架中render函数里返回的jsx代码部分
  3. 数据+模板,结合生成真实dom并显示
<div>
     1111
  	 <p>2222</p>
</div>
  1. 生成虚拟dom,即一个js对象,用来描述真实dom(损耗性能,但相对生成新的真实dom元素还是比较节省的)
{
    tagName: 'div',
    attr: 1111,
    children: {
      tagName: 'p',
      attr: 2222
    }
  1. state变化后,假设p标签内容变为“3333”
  2. 数据+模板,生成新的虚拟dom(极大提升性能)
{
    tagName: 'div',
    attr: 1111,
    children: {
      tagName: 'p',
      attr: 3333
	}
}
  1. 比较新旧dom的区别
  2. 直接操作dom,改变p标签中的内容

4. React底层实现

  1. 定义state数据
  2. jsx模板
  3. 数据+模板,结合生成生成虚拟dom
{
    tagName: 'div',
    attr: 1111,
    children: {
      tagName: 'p',
      attr: 2222
    }
  1. 用虚拟dom的结构生成真实的dom来显示
<div>
     1111
  	 <p>2222</p>
</div>
  1. state变化后,假设p标签内容变为“3333”
  2. 数据+模板,生成新的虚拟dom(极大提升性能)
{
    tagName: 'div',
    attr: 1111,
    children: {
      tagName: 'p',
      attr: 3333
	}
}
  1. 比较新旧dom的区别
  2. 直接操作dom,改变p标签中的内容

因此,在render函数中,标签并不是真实标签,而是虚拟dom。整个的过程是:JSX -> React.createElement -> JS对象(虚拟dom)-> 真实dom

三、虚拟DOM优点

  1. 提升性能
  2. 使得跨端应用得以实现,如React Native框架的使用开发app

四、Diff算法

寻找原始虚拟DOM和新的虚拟DOM差异的算法

比对方法:同层比对
在这里插入图片描述
过程:
(1)React通过updateDepth对Virtual DOM树进行层级控制。
(2)对树分层比较,两棵树只对同一层次节点 进行比较。如果该节点不存在时,则该节点及其子节点会被完全删除,不会再进一步比较。
(3)只需遍历一次,就能完成整棵DOM树的比较。

特点:如果只有根节点相同,则会渲染所有子节点,会有性能损耗,但算法简单,比对速度快

diff算法参考链接:https://www.jianshu.com/p/3ba0822018cf

关于key值的设置------为何在组件循环渲染时要设置key值?
在这里插入图片描述
对于每个组件,如果设置了一个key值,就能直接通过key值来比对其value相对于原始value是否改变,提升了性能。

关于key值的设置------为何在组件循环渲染时不能用下标作为key值?

举个栗子,循环需要渲染一个list的内容成为三个组件,内容分别是:

a,b,c

用下标作为key值时,对应的key值为:

0-->a,1-->b,2-->c

当删除a后,对应的key值为:

0-->b,1-->c

因此,原始的b、c对应的key值发生了变化,key值变得不稳定,背离了根据key值进行比对的初衷(虽然有时候不会出现问题,但一旦出现问题便难以发现)

五、对 setState 的认知:

  1. setState 不会立刻改变React组件中state的值.
  2. setState 通过触发一次组件的更新来引发重绘.
  3. 多次 setState 函数调用产生的效果会合并。
    在这里插入图片描述
    重绘指的就是引起 React 的更新生命周期函数4个函数:
  • shouldComponentUpdate(被调用时this.state没有更新;如果返回了false,生命周期被中断,虽然不调用之后的函数了,但是state仍然会被更新)
  • componentWillUpdate(被调用时this.state没有更新)
  • render(被调用时this.state得到更新)
  • componentDidUpdate 如果每一次 setState 调用都走一圈生命周期,光是想一想也会觉得会带来性能的问题,其实这四个函数都是纯函数,性能应该还好,但是render函数返回的结果会拿去做Virtual DOM比较和更新DOM树,这个就比较费时间。

目前React会将setState的效果放在队列中,积攒着一次引发更新过程。为的就是把 Virtual DOM 和 DOM 树操作降到最小,用于提高性能。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值