本章内容
目录
- 一、为什么需要"虚拟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",原生应用中转化为原生的"组件"
到此,本章内容结束!