前提:
接下来的学习目标是为了写一个toy-react
- 我们将会了解什么是Virtual DOM
- Virtual DOM是如何提升操作DOM性能的
- 如何创建Virtual DOM对象,如何将Virtual DOM对象转化为真实DOM对象
- 以及如何对比Virtual DOM从而找出差异部分,实现最小化DOM更新
- 如何渲染函数组件和类组件
- 如何调用类组件的生命周期函数
- 还需要熟悉在组件中如何通过ref属性获取元素或者组件的实例对象
我们会通过toy-react,最终实现一个todolist,通过实战让我们更好的了解通过Diff算法和Virtual DOM是怎样对DOM对象的增删改查操作以提升JavaScript操作DOM对象的性能的。在文章最后会贴上toy-react模板和toy-react项目。开始学习!!!
JSX到底是什么
弄清楚JSX是什么对我们学习Virtual DOM有着重要的意义,JSX看起来像HTML而已,但是不是HTML。JSX实际上是JavaScript代码,是React团队创造的一种JavaScript的语法扩展,用于来描述用户界面的。他的出现是为了React开发者能够在JavaScript当中更好更方便的去描述用户界面,但是浏览器是不认识JSX的,不能够执行它的。所以在JSX执行之前babel会去先编译JSX代码,将其编译成浏览器能够执行的JavaScript代码!
// 这是JSX,相信看了上节文章的人应该有个印象
<div className="container">
<h3>Hello React</h3>
<p>React is great</p>
</div>
复制代码
babel编译后
React.createElement (
"div",
{
className: "container"
},
React.createElement("h3", null, "Hello React"),
React.createElement("p", null, "React is great")
)
复制代码
React.createElement方法第一个参数是节点类型,值为节点名称字符串的形式,第二个参数是节点属性,第三个后之后的参数都是当前节点的子节点.
React.createElement这个方法就是用来创建Virtual DOM对象,其实也就是JavaScript对象,这就是使用JavaScript对象来描述DOM对象的一种实现方式。React.createElement的返回值呢就是Virtual DOM,然后React会将 VirtualDOM转化为真实DOM对象,再将真实DOM显示在页面当中。这就是JSX转换的过程
如果React开发人员使用下面的写法描述用户界面就太繁琐了!!!
我们可以使用Babel REPL来体验一下JSX转化js代码是怎么样的
DOM操作问题
用脚本进行DOM操作的代价很昂贵。有个贴切的比喻,把DOM和JavaScript各自想象为一个岛屿,它们之间用收费桥梁连接,js每次访问DOM,都要途径这座桥,并交纳“过桥费”,访问DOM的次数越多,费用也就越高。 因此,推荐的做法是尽量减少过桥的次数,努力待在ECMAScript岛上。
现代浏览器使用JavaScript操作DOM是必不可少的,但是这个动作是非常消耗性能的,因为使用JavaScript操作DOM对象要比JavaScript操作普通对象要慢很多,页面如果频繁的DOM操作会造成页面卡顿,应用流畅度降低,造成非常不好的体验。
大多数的JavaScript框架对于DOM的更新都会远远超过必须进行的更新,从而使得这种缓慢操作变得更糟,例如假设你有包含是个项目的列表,你仅仅更改了列表中的一项大多数JavaScript框架会重建整个列表,这比必要的工作要多十倍,更新效率低下已经成为严重的问题
因为这个原因react的虚拟dom就显得难能可贵了,它创造了虚拟dom并且将它们储存起来,每当状态发生变化的时候就会创造新的虚拟节点和以前的进行对比,让变化的部分进行渲染.大大提高了JavaScript操作DOM的效率,那接下来我们了解下Virtual DOM是什么
Virtual DOM 是什么
Virtual DOM对象实际上就是JavaScript对象,使用JavaScript对象来描述DOM对象信息,比如DOM对象的类型是什么,他身上有哪些属性,它拥有哪些子元素。
也可以把Virtual DOM对象理解为DOM对象的副本,但是不能直接显示在屏幕上
<div className="container">
<h3>Hello React</h3>
<p>React is great </p>
</div>
复制代码
下面就是virtual DOM对象,type属性表示节点的类型信息,props属性表示节点的属性信息,用children属性表示节点的子节点信息。节点的文本信息也断是props属性里面的textContent。可以对应上面JSX,看看对应virtral DOM对象的基本结构
{
type: "div",
props: { className: "container" },
children: [
{
type: "h3",
props: null,
children: [
{
type: "text",
props: {
textContent: "Hello React"
}
}
]
},
{
type: "p",
props: null,
children: [
{
type: "text",
props: {
textContent: "React is great"
}
}
]
}
]
}
复制代码
了解完Virtual DOM之后,再来熟悉Virtual DOM是如何提升效率的
Virtual DOM 如何提升效率
最核心的原则就是最小化DOM操作,精准找出发生变化的DOM对象,只更新发生变化的部分。
在React第一次创建DOM对象后,会为每个DOM对象创建其对应的Virtual DOM对象,在DOM对象发生更新之前,React会先更新所有的Virtual DOM对象,让后React会将更新后的Virtual DOM和更新前的Virtual DOM进行比较,从而找出发生变化的部分,React会将发生变化的部分更新到真实的DOM对象中,React仅更新必要更新的部分,从而提高了JavaScript操作DOM的性能。操作virtualDOM的时候就是JavaScript操作JavaScript对象是非常快的,几乎可以忽略不计,因为Virtual DOM 对象的更新和比较仅发生在内存中,不会在视图中渲染任何内容,所以这一部分的性能损耗成本是微不足道的。
左边是Virtual DOM,右边是Real DOM,React会拿更新前的virtral DOM和更新后的 Virtual DOM进行比对,发现在整个DOM树种删除了两个节点,React在更新真实DOM对象的时候,就只会删除这两个节点,而不是更新整个DOM树,从而提高了DOM操作性能
更新前JSX
<div id="container">
<p>Hello React</p>
</div>
复制代码
更新后JSX
<div id="container">
<p>Hello Angular</p>
</div>
复制代码
可以看出是p标签里面的文本发生了变化,下面可以看一下虚拟DOM是如何进行对比的
更新前的虚拟DOM
const before =
type: "div",
props: { id: "container" },
children: [
{
type: "p",
props: null,
children: [
{ type: "text", props: { textContent: "Hello React" } }
]
}
]
}
复制代码
更新后的虚拟DOM
const after = {
type: "div",
props: { id: "container" },
children: [
{
type: "p",
props: null,
children: [
{ type: "text", props: { textContent: "Hello Angular" } }
]
}
]
}
复制代码
这两个虚拟DOM会进行对比,很容易看出只有子节点里面的内容发生改变,React只会将这个改变的内容节点更新到真实DOM中,这样就起到了提高操作DOM的效率。
小结
现在我们就真正知道什么是Virtual DOM对象了,实际上就是JavaScript对象,使用JavaScript对象来描述真实dom对象的一种方式,我们还清楚了它是如何提高操作DOM效率了,就是通过对比新老Virtual DOM对象从中找出差异,最终只更新DOM对象差异的部分,从而提升JavaScript操作DOM的效率。
好了今天就暂且学到着,可以体会一下Virtual的原理,第三天我们来看怎么创建一个虚拟DOM对象,敬请期待!!!