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

本章内容

目录

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

上一节我们讲了 state、props与render函数的关系,本节内容开始了解 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 Application的API,性能消耗极大

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

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

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

到此,本章内容结束!

相关推荐
FRing034 分钟前
JavaScript入门到精通三十三(异常处理、call方法、apply方法、bind方法、防抖、节流)
开发语言·前端·javascript
计算机魔术师1 小时前
OpenAI 砍掉 100 亿融资目标,AI 资本市场的温度计变了
前端
jktantan1 小时前
(二)Vue 3 的 attrs 不是响应式:el-form 扩展属性同步的三种方案
前端·javascript·vue.js·element-plus
前端 贾公子2 小时前
第 5 章:Codex 从可运行程序到可交付工具
java·前端·数据库
用户360055579002 小时前
Kestrel_VLLM - 26 · 发射空档三步曲:事件计时 → nsys → 判别实验
前端
echome8882 小时前
JavaScript async/await 错误处理:别让 Promise 静默失败
开发语言·前端·javascript·promise
PedroQue992 小时前
v0.2.0 架构升级:class + reactive 重塑状态管理
前端·uni-app
鶴哥只手遮天2 小时前
Angular 22 源码级深度解析-第 02 章 编译链路总览:从模板字符串到 `ɵɵ` 指令
前端·开源·angular.js
尘世中一位迷途小书童2 小时前
别再堆万字 Prompt:用 Agent Skills 给团队写一个「前端 Review」Skill
前端·ai编程·cursor
aixingpan2 小时前
aixingpan.cn API开发文档:api_docs_bichart_common2接口指南
前端·php