React进阶 - 13(说一说 React 中的虚拟 DOM)

本章内容

目录

    • 一、为什么需要"虚拟DOM"
    • [二、虚拟 DOM" 带来的希望](#二、虚拟 DOM“ 带来的希望)
    • [三、虚拟 DOM" 的优势(性能大幅度提升 & 跨端应用)](#三、虚拟 DOM“ 的优势(性能大幅度提升 & 跨端应用))

上一节我们讲了 statepropsrender函数的关系,本节内容开始了解 React中的"虚拟 DOM" 相关知识。

一、为什么需要"虚拟DOM"

  • 上篇文章,我们知道:当组件的 state或者 props变化时,render函数会重新知己,界面也重新被渲染。
  • 然而,我们要知道,页面的重新渲染这个过程是非常耗性能的。
  • 假设没有 React, 我们要实现数据变化界面也随着变化,通常可以这么做
text 复制代码
方式一:
1、定义一个 state 数据
2、定义一个 "JSX模版"
3、将"数据+JSX模版"结合,生成真实 DOM 来显示
4、当数据变化时
5、"数据+JSX模版"相结合,生成真实DOM,替换原始 DOM
6、如此往复循环 4、5步骤

方式二:(对方式一进行优化下,不直接替换旧的 DOM,只替换变化的数据节点)
1、定义一个 state 数据
2、定义一个 "JSX模版"
3、将"数据+JSX模版"结合,生成真实 DOM 来显示
4、当数据变化时
5、"数据+JSX模版"相结合,生成真实 DOM
6、新的 DOM 和旧 DOM比对,找到只变化的节点
7、用新 DOM 变化的节点替换旧 DOM 变化处的节点
8、如此往复循环 5、6、7步骤


方式二相对于方式一的步骤增加了,但是性能会有所提升(局部替换比整体替换消耗的性能更少),但是方式二的比较过程同样耗费了些性能,这样来看,性能也没提升多少

二、虚拟 DOM" 带来的希望

基于上述的痛点,React提出了"虚拟 DOM"的方案。也就是方式三:

  • 1、定义一个 state数据
js 复制代码
this.state = {
  content: 'hello'
}
  • 2、定义一个 JSX 模版
js 复制代码
render() {
 return (
  <div id="d1">
    <span>{content}</span>
  </div>
 )
}
  • 3、"数据+JSX模版"结合,React底层会调用 React.createElement()接口,将 JSX 模版变成一个原始的"虚拟DOM"(虚拟DOM 本质是一个数组形式的 JS对象,用它来描述"真实的DOM")
text 复制代码
虚拟 DOM 格式:[标签名,标签属性,标签的子节点]

注意如果标签子节点又是一个完整的 DOM,那么还是遵循 "[标签名,标签属性,标签的子节点]" 的格式

那将 2中的"JSX模版"转为"JS对象"的底层实现。运行后发现,我们可以通过 React.createElement()来实现 JSX的功能。唯一的缺点就是很复杂,所以这也是为什么 JSX存在的原因,它是一个更加简便好用的方式

js 复制代码
// 1、注释掉这里,改用下面的 React.createElement方式实现
// render() {
//  return (
//   <div id="d1">
//     <span>{content}</span>
//   </div>
//  )
// }

// 2、使用 React.createElement方式实现上面注释的功能
render() {
 // 我们将"JSX 模板"用 craeteElement 方法来改写,其接收 3 个参数依次是:元素的标签名、标签的属性、元素的children 子节点
 return React.createElement("div", {id: "d1", React.createElement("span", {}, "hello")})
}

上面生成的"虚拟DOM"为:["div", {id: "d1"}, ["span", {}, "hello"]]

  • 4、根据上面的"虚拟DOM"生成"真实DOM"
html 复制代码
 <div id="d1">
    <span>{content}</span>
  </div>
  • 5、当数据 state变化
js 复制代码
this.state = {
  content: 'hello world'
}
  • 6、重复 3步骤,生成新的"虚拟DOM": ["div", {id: "d1"}, ["span", {}, "hello world"]]

  • 7、比较"旧的虚拟DOM"和"新的虚拟DOM",找到 span中的内容是有变更的

  • 8、直接操作 DOM,改变 span里的内容

三、虚拟 DOM" 的优势(性能大幅度提升 & 跨端应用)

  • "虚拟DOM"本质上是用 JS生成的一个 JS对象,这个转变消耗的性能较少。如果直接使用 JS生成一个 DOM元素,那么它是会底层调用 Web ApplicationAPI,性能消耗极大

  • 然后两个"虚拟DOM"之间比对,本质是 js对象的比对,其底层使用的"Diff算法"是不怎么消耗性能的。如果直接把两个"真实 DOM"进行比对,其性能消耗极大

  • "JS 对象"不仅可以让"浏览器"识别,在原生应用(Android IOS)上也可以(注意:"原生应用"里不存在 DOM的概念,所以真实的 DOM在原生应用中不被识别,无法使用),因此,有了"虚拟DOM"后,我们用它生成一些原生组件。

  • 这样的话,在复用"state"、"JSX模版"等代码优势下,让"虚拟DOM"在不同"端"中进行转化:网页端转化为"真实DOM",原生应用中转化为原生的"组件"

到此,本章内容结束!

相关推荐
旧味清欢|1 分钟前
关注分离(Separation of Concerns)在前端开发中的实践演进:从 XMLHttpRequest 到 Fetch API
javascript·http·es6
热爱编程的小曾19 分钟前
sqli-labs靶场 less 8
前端·数据库·less
gongzemin30 分钟前
React 和 Vue3 在事件传递的区别
前端·vue.js·react.js
Apifox43 分钟前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
-代号95271 小时前
【JavaScript】十四、轮播图
javascript·css·css3
树上有只程序猿1 小时前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼2 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
QTX187302 小时前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下2 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox2 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员