虚拟 DOM 是一个基本的 React 概念。如果您在过去几年编写过 React 代码,您可能听说过它。但是,你可能不明白它是如何工作的以及 React 为何使用它。

本文将介绍什么是虚拟 DOM,它在 React 中的好处,以及帮助解释这个概念的实用示例代码。

在本文中:

  • 概念回顾:DOM 是什么?

    • 重新渲染如何影响性能

    • React 中的重新渲染:为什么要使用虚拟 DOM

  • React 中的虚拟 DOM

    • React 如何实现虚拟 DOM

  • 回顾虚拟 DOM 以及为什么在 React 中使用它

概念回顾:DOM 是什么?

要了解虚拟 DOM 并了解 React 实现它的原因,让我们刷新对实际浏览器 DOM 的了解。

每当在浏览器中加载 Web 文档(例如 HTML)时,就会以树状结构创建文档元素的基于对象的表示。这种对象表示称为文档对象模型,也称为 DOM。

由于其基于对象的特性,JavaScript 和其他脚本语言理解 DOM,并且可以交互和操作文档内容。例如,使用 DOM,开发人员可以添加或删除元素、修改其外观以及对 Web 元素执行用户操作。

DOM 查询和更新之类的 DOM 操作更轻,因此非常快。但是,为了使更新反映在网页上,必须重新渲染该页面。

重新渲染如何影响性能

重新渲染页面以反映 DOM 更新的成本很高,并且可能导致性能下降,因为浏览器必须重新计算 CSS,重新运行每个可见元素的布局,并重新绘制网页。

让我们用下面的 JavaScript 代码模拟一个重新渲染的页面:

const update = () => {const element = `<h3>JavaScript:</h3><form><input type="text"/></form><span>Time: ${new Date().toLocaleTimeString()}</span>`;
​document.getElementById("root1").innerHTML = element;
};
​
setInterval(update, 1000);

你可以在 CodeSandbox 上看到完整的代码。

表示文档的 DOM 树如下所示:

通过在代码中使用setInterval()回调,我们每秒都在渲染 UI 的状态。正如我们在下面的 GIF 中看到的,在指定的时间间隔之后,浏览器会重新渲染、运行布局和重新绘制网页,以及其他操作。

浏览器 DOM 没有机制来比较和对比已更改的内容并仅重新绘制该 DOM 节点(在本例中为渲染时间):

这种重新渲染在文本输入中很明显。正如我们所看到的,输入字段总是在设置的时间间隔后被清除。DOM 操作后在浏览器中的重新渲染过程会导致性能缺陷。

React 中的重新渲染:为什么要使用虚拟 DOM

众所周知,React 是一个基于组件的库。如果 state 或 prop 发生变化,或者它的父组件重新渲染,React 组件自然会重新渲染。

React 无法承受每次重新渲染后重新绘制所有 DOM 节点的成本。为了克服这一挑战,React 实现了虚拟 DOM 的概念。


超过 20 万开发人员使用 LogRocket 来创造更好的数字体验了解更多 →


React 不是允许浏览器在每次重新渲染或 DOM 更新后重新绘制所有页面元素,而是使用虚拟 DOM 的概念来确定发生了哪些变化而不涉及实际 DOM,然后确保实际 DOM 只重新绘制必要的数据。

这个概念有助于 React 优化性能。

React 中的虚拟 DOM

React 中的虚拟 DOM 是实际 DOM 的“虚拟”表示。它只不过是为复制实际 DOM 而创建的对象。

与实际的 DOM 不同,虚拟 DOM 的创建成本很低,奇妙搜索App,搜遍全球ED2k网络资源,聚合30多个API资源接口!因为它不会写入屏幕。它仅可用作一种策略,以防止在重新渲染期间重绘不必要的页面元素。

看一下代表前面 JavaScript 示例的 React 版本的以下渲染代码:

// ...
const update = () => {const element = (<><h3>React:</h3><form><input type="text" /></form><span>Time: {new Date().toLocaleTimeString()}</span></>);root.render(element);
};

为简洁起见,我们删除了一些代码。你可以在 CodeSandbox 上看到完整的代码。

我们也可以用纯 React 编写 JSX 代码,如下所示:

const element = React.createElement(React.Fragment,null,React.createElement("h3", null, "React:"),React.createElement("form",null,React.createElement("input", {type: "text"})),React.createElement("span", null, "Time: ", new Date().toLocaleTimeString())
);

请注意,您可以通过将 JSX 元素粘贴到babel repl 编辑器中来获得与 JSX 代码等效的 React 代码。

现在,如果我们在控制台中记录 React 元素:

 const element = (<><h3>React:</h3><form><input type="text" /></form><span>Time: {new Date().toLocaleTimeString()}</span></>);console.log(element)

我们会有这样的东西:

如上所示,该对象是虚拟 DOM。

React 如何实现虚拟 DOM

当我们渲染用户界面时,会创建一个用于该渲染的虚拟 DOM 并将其保存在内存中。如果渲染中发生更新,React 会自动为更新创建一个新的虚拟 DOM 树。

为了帮助进一步解释这一点,让我们像这样直观地表示虚拟 DOM:

但是,不要忘记虚拟 DOM 只是一个代表 UI 的简单对象。屏幕上没有绘制任何内容,因此很容易创建。


来自 LogRocket 的更多精彩文章:

  • 不要错过来自 LogRocket 的精选时事通讯The Replay

  • 了解LogRocket 的 Galileo 如何消除噪音以主动解决应用程序中的问题

  • 使用 React 的 useEffect优化应用程序的性能

  • 在多个 Node 版本之间切换

  • 了解如何使用 AnimXYZ 为您的 React 应用程序制作动画

  • 探索 Tauri,一个用于构建二进制文件的新框架

  • 比较NestJS 与 Express.js


在 React 创建新的虚拟 DOM 树后,它会使用差异算法将其与之前的快照进行比较,以确定哪些更改是必要的。

然后它使用一个名为 ReactDOM 的库来确保实际的 DOM 只接收和重绘更新的一个或多个节点。这个过程称为和解。

当 React 实现 diffing 算法时,它首先比较两个快照是否具有相同的根元素。

如果它们具有相同的元素,React 会继续并递归属性,然后是 DOM 节点的子节点。如果根元素是不同类型的——这在大多数更新中很少见——React 将销毁旧的 DOM 节点并构建一个新的 DOM 树。

如果我们检查我们的 React 渲染,我们将得到以下行为:

在每次渲染时,React 都有一个虚拟 DOM 树,它与之前的版本进行比较以确定哪些节点内容得到更新,并确保更新的节点与实际 DOM 匹配。

在上面的 GIF 中,我们可以看到只有状态发生变化的渲染时间会在每次重新渲染时重新绘制。

在下面的另一个示例中,我们渲染了一个简单的 React 组件,该组件在单击按钮后更新组件状态:

import { useState } from "react";
​
const App = () => {const [open, setOpen] = useState(false);
​return (<div className="App"><button onClick={() => setOpen((prev) => !prev)}>toggle</button><div className={open ? "open" : "close"}>I'm {open ? "opened" : "closed"}</div></div>);
};
export default App;

如前所述,更新组件状态会重新渲染组件。然而,如下所示,在每次重新渲染时,React 只知道更新类名和更改的文本。

请参阅CodeSandbox 上的代码和演示。

回顾虚拟 DOM 以及为什么在 React 中使用它

每当我们在 React 中操作虚拟 DOM 元素时,我们都会绕过直接操作实际 DOM 时所涉及的一系列操作。

这是可能的,因为使用虚拟 DOM,屏幕上不会绘制任何内容。此外,通过 diffing 算法,React 可以最终确定哪些更新是必要的,并且只更新真实 DOM 上的对象。

React 中虚拟 DOM 的概念无疑有助于降低重新渲染网页的性能成本,从而最大限度地减少重新绘制屏幕所需的时间。

这里有一个简单的类比来进一步巩固我们对虚拟 DOM 的知识:将操作虚拟 DOM 视为编辑结构设计或蓝图,而不是重建实际结构。

与每次发生更新时重建结构相比,编辑蓝图以包含更新非常便宜。当蓝图被修改和定稿时,我们就可以只包括对实际结构的更新。

结论

Virtual DOM 只不过是 React 用来优化应用程序性能的一种策略。它提供了一种机制,可以比较两个渲染树以了解究竟发生了什么变化,并且只更新实际 DOM 上必要的内容。

和 React 一样,Vue 和其他一些框架也采用了这种策略。但是,Svelte 框架提出了另一种方法来确保优化应用程序。相反,它将所有组件编译成独立的微型 JavaScript 模块,使脚本非常轻巧且运行迅速。

React 中的虚拟 DOM 是什么?相关推荐

  1. [react] 什么是虚拟dom?虚拟dom比操作原生dom要快吗?虚拟dom是如何转变成真实dom并渲染到页面的?

    壹 ❀ 引 虚拟DOM(Virtual DOM)在前端领域也算是老生常谈的话题了,若你了解过vue或者react一定避不开这个话题,因此虚拟DOM也算是面试中常问的一个点,那么通过本文,你将了解到如下 ...

  2. React简介、虚拟DOM、Diff算法、创建React项目、JSX语法、组件、组件声明方式、组件传值props和state、组件的生命周期

    React简介: 前面只是简单介绍移动APP开发,后面还会继续深入介绍移动app开发:其中想要用ReactNative开发出更出色的应用,那么就得学好React,下面将介绍React: React 是 ...

  3. [react] 为何说虚拟DOM会提高性能?

    [react] 为何说虚拟DOM会提高性能? 虚拟dom相当于在js和真实dom中间加了一个缓存,利用dom diff算法避免了没有必要的dom操作,从而提高性能 个人简介 我是歌谣,欢迎和大家一起交 ...

  4. 浅谈Vue中的虚拟DOM

    Virtual DOM 是JavaScript按照DOM的结构来创建的虚拟树型结构对象,是对DOM的抽象,比DOM更加轻量型 为啥要使用Virtual DOM 当然是前端优化方面,避免频繁操作DOM, ...

  5. 简单实现Vue中的虚拟dom

    简单实现Vue中的虚拟dom 传送门:简单实现Vue中的插值替换(三) 前言: 要想简单实现虚拟dom,首先我们要了解虚拟dom,知道自己要实现的是个什么东西. 说起来,我刚开始学习Vue的时候对虚拟 ...

  6. vue 中的虚拟dom树

    虚拟DOM树其实就是一个普通的js对象,它是用来描述一段HTML片段的 当页面渲染的时候Vue会创建一颗虚拟DOM树 当页面发生改变Vue会再创建一颗新的虚拟DOM树 前后两颗新旧虚拟DOM树进行对比 ...

  7. vue中的虚拟DOM原理

    1.定义: 虚拟DOM其实就是用一个原生的JS对象去描述一个DOM节点,实际上它只是对真实 DOM 的一层抽象.最终可以通过一系列操作使这棵树映射到真实环境上. 相当于在js与DOM之间做了一个缓存, ...

  8. Vue中的虚拟DOM

    文章目录 一.什么是虚拟DOM 二.虚拟DOM的作用 提高性能 三.通过模板转换成视图来理解 一.什么是虚拟DOM 我们都知道DOM是什么,它是实实在在的被渲染在页面上的,我们平时的操作都和DOM息息 ...

  9. React开发(140):react中ref为dom添加ref

最新文章

  1. PhD养成记 | 于歆杰:如何有效获取、归档和阅读文献
  2. insert---插入记录
  3. UE4 Fix – “Lighting build failed. Swarm failed to kick off.”
  4. 什么是HBase?它是怎样工作的?终于有人讲明白了
  5. [技术分享]【DLI跨源】当DLI遇见MongoDB
  6. Android近场通信---NFC基础(三)
  7. html输入地址提示错误,高德地图开发之输入框内伴随地址的输入,动态给出地址选择提示...
  8. linux 进程退出原因,linux – 为什么waitpid不等待进程退出?
  9. html5实例-闪烁的星星
  10. kite插件~快速提高代码速度
  11. 洛谷P4867 Gty的二逼妹子序列(莫队+树状数组)
  12. Vensim模拟结果vdf数据文件转化为可读文本文件
  13. python人脸对比相似度_Python比较两个图片相似度的方法
  14. DHCP工作原理和报文格式
  15. java微信支付详解_java微信支付接入流程详解
  16. HTML5 video(PC和移动端)自动播放学习指北
  17. 一款基于springboot开发的经典后台管理系统
  18. linux kde vga参数1366,Archlinux+KDE 下双屏VGA高分辨率设置
  19. Photoshop----图层混合模式详解
  20. AppStore 算法更新,ASO优化师新建议:如何快速上榜,避免掉词?

热门文章

  1. B树和B+树傻傻分不清楚?
  2. [附源码]Node.js计算机毕业设计成都美食交流平台Express
  3. 试用华硕 WL-566gM之外观篇
  4. pybullet GGCNN数据集制作(三)
  5. Brew平台音乐播放器Dream Player
  6. yarn command ‘xxx‘ not found
  7. bugku——聪明的小羊(栅栏密码)
  8. UE4 OpenGL坐标系
  9. 我用Java抢到了一个手机靓号~
  10. MATLAB高效编程技巧与应用:25个案例分析