React 中的 Dom 是什么?2025年3月17日 | 阅读13分钟 真实/浏览器 DOMDOM 代表“文档对象模型”(Document Object Model)。它是网页或应用程序中 HTML 的结构化表示。它将Web 应用程序的整个 UI(用户界面)表示为树形数据结构。 简单来说,它是 Web 应用程序中 HTML 元素的结构化表示。 ![]() 每当应用程序 UI 的状态发生任何变化时,DOM 都会更新并表示该变化。每次变化都会渲染和操作 DOM 以更新应用程序的用户界面,这会影响性能并使其变慢。 因此,对于许多 UI 组件和复杂的 DOM 结构,更新将更加昂贵,因为它需要在每次更改时重新渲染。 DOM 由树形数据结构构成。它包含网页文档中存在的每个 UI 元素的节点。 更新 DOM如果您了解一些 JavaScript,您可能会看到人们使用 'getElementById()' 或 'getElementByClass()' 方法来修改 DOM 的内容。 每当应用程序的状态发生任何变化时,DOM 都会更新以反映 UI 的变化。 虚拟 DOM 如何加速当任何新内容添加到应用程序时,会创建一个虚拟 DOM,表示为一棵树。应用程序中的每个元素都是树中的一个节点。 因此,每当元素的位置发生变化时,都会创建一个新的虚拟 DOM。将较新的虚拟 DOM 树与最新的进行比较,并记录下变化。 它会找到对实际 DOM 进行这些更改的最可能方式。然后,更新后的元素将在页面上重新渲染。 虚拟 DOM 如何在 React 中提供帮助在 React 中,一切都被视为一个组件,一个函数式组件或一个类组件。一个组件有一个状态。每当我们更改 JSX 文件中的某些内容时,简单来说,每当组件的状态发生变化时,React 就会更新其虚拟 DOM 树。 React 每次都维护两个虚拟 DOM。第一个包含更新后的虚拟 DOM,另一个是更新后的虚拟 DOM 的预更新版本。它将预更新版本的虚拟 DOM 与更新后的版本进行比较,并找出 DOM 中发生了什么变化,比如哪些组件将被更改。 虽然这看起来可能效率不高,但成本并不高,因为更新虚拟 DOM 不会花费太多时间。 当将当前的虚拟 DOM 树与前一个进行比较时,这个过程被称为“差异比较”(diffing)。一旦 React 知道发生了什么变化,它就会更新实际 DOM 中的对象。React 使用批量更新来更新实际 DOM。对实际 DOM 的更改是分批发送的,而不是为组件状态的单个更改发送任何更新。 重新渲染 UI 是最昂贵的部分,React 通过确保真实 DOM 接收批量更新来重新渲染 UI,从而以最高效的方式进行管理。将更改转换为实际 DOM 的过程称为协调 (reconciliation)。 它提高了性能,是开发者喜爱 React 及其虚拟 DOM 的主要原因。 React 的虚拟 DOM 是什么?虚拟 DOM 的概念旨在使真实 DOM 的性能更好更快。虚拟 DOM 是 DOM 的一个虚拟表示。 但主要区别在于,每次发生变化时,更新的是虚拟 DOM,而不是实际 DOM。 例如,真实 DOM 和虚拟 DOM 都表示为树形结构。树中的每个元素都是一个节点。当一个新项目添加到应用程序 UI 时,一个节点会被添加到树中。 如果任何元素的位置发生变化,就会创建一个新的虚拟 DOM 树。虚拟 DOM 会计算在真实 DOM 上进行更改所需的最小操作数。它通过减少重新渲染整个真实 DOM 的成本和操作,从而提高了效率和性能。 ![]() 现在我们对真实 DOM 和虚拟 DOM 有了基本的了解。 让我们看看 React 是如何通过使用虚拟 DOM 来工作的。
![]() 在图中,深蓝色的圆圈是已更改的节点。这些组件的状态发生了变化。React 计算前一个和当前版本的虚拟 DOM 树之间的差异,然后重新渲染整个父子树以显示已更改的 UI。 更新后的树会批量更新(即对真实 DOM 的更新是分批发送的,而不是为每个状态变化发送更新)到真实 DOM。 要更深入地了解这一点,我们需要了解 React 的 render() 函数。 然后,我们需要了解一些 React 的重要特性。 JSXJSX 代表 JavaScript XML。它是 JS 的一种语法扩展。使用 JSX,我们可以在包含 JavaScript 代码的文件中编写 HTML 结构。 组成部分组件是独立且可重用的代码块。React 应用中的每个用户界面都是一个组件。一个应用程序可以有许多组件。 组件分为两种类型,类组件和函数式组件。 类组件是有状态的,因为它们使用自己的“状态”来改变用户界面。函数式组件是无状态组件。它们的行为类似于 JavaScript 函数,接受一个任意参数,称为“props”。 引入了 React Hooks 以便在函数式组件中使用状态。 生命周期方法生命周期方法是 React 内置的重要方法,它们在组件在 DOM 中的整个生命周期内对组件进行操作。React 的每个组件都经历一个事件生命周期。 render() 方法是使用最广泛的生命周期方法。 它是React 类组件中唯一必须的方法。因此,在每个类组件中都会调用 render()。 render() 方法处理组件在 UI 上的渲染。render() 包含所有要显示在屏幕上的逻辑。如果不想在显示屏上显示任何内容,它也可以返回一个null值。 示例如下 该示例将展示在 render() 中编写的 JSX。 当组件内的状态或属性更新时,render() 将返回一个不同的 React 元素树。 当在控制台或 JavaScript 文件中编写代码时,会发生以下情况:
最后,遍历树以在屏幕上显示。 所以我们知道更新 DOM 涉及到更改内容。它与此联系更紧密。 重新计算 CSS 和更改布局涉及复杂的算法,这会影响性能。 因此,React 有许多方法来处理它,因为它使用了所谓的虚拟 DOM。 react-domreact-dom 包在应用程序的顶层提供了特定于 DOM 的方法,以便在需要时跳出 React 模型。 如果您使用 ES5 和 npm,您还应该这样写: react-dom 包还提供了特定于客户端和服务器应用程序的模块
react-dom 包导出了这些方法
react-dom 方法也已导出
注意:hydrate 和 render 都已被新的客户端方法取代。浏览器支持React 支持所有现代浏览器,对于旧版本则需要一些 polyfill。 注意:我们不支持不支持 ES5 方法的旧版浏览器,例如 Internet Explorer。如果页面中包含了像 es5-shim 和 es5-sham 这样的 polyfill,您可能会发现在最新的浏览器中应用程序可以工作,但如果您选择这条路,后果自负。引用createPortal() createPortal() Portal 提供了一种将子元素读入 DOM 节点的方法,该节点存在于 DOM 组件的层级之外。 flushSync() 强制 React 在提供的回调中同步更新。它确保 DOM 立即更新。 注意
遗留 API 参考render() 注意:在 React 中,Render 已被 createRoot 取代。将一个 React 元素渲染到所提供容器的 DOM 中,并返回对该组件的引用。如果一个 React 元素之前已经渲染到任何容器中,它将对其执行更新,并且有必要反映最新的 React 元素。 如果提供了可选的回调,它将在组件渲染时执行。 注意 render() 方法控制着它所传递的容器节点的内容。任何现有的 DOM 元素都会被替换。 Render() 不会改变容器节点(它只能修改容器的子节点)。它可能可以在不覆盖子元素的情况下将组件插入到现有的 DOM 节点中。 Render() 当前返回对 ReactComponent 的根实例的引用。 然而,它的返回值是继承的,应该避免使用,因为在某些情况下,未来版本的 React 可能会异步生成组件。 如果您需要对 ReactComponent 原型的引用,最好的解决方案是为元素附加一个回调引用。 Render() 用于对服务器上渲染的容器进行 hydrate 的用法已过时。请使用 hydrateRoot() 代替。 hydrate()hydrate 已被 hydrateRoot 取代。 它与 render() 完全相同,但用于 HTML 内容由 ReactDOMServer 渲染的容器。React 将尝试将事件监听器附加到当前标记上。 注意 React 期望渲染的内容在服务器和客户端之间是相同的。我们可以纠正文本内容,但必须将不一致视为错误并加以修正。在开发模式下,React 会在 hydrate 期间对不一致发出警告。 无法保证特定的差异会因不一致而被修正。 出于性能原因,在大多数应用程序中这很重要,而且验证所有标志的成本太高。 假设元素的属性或文本内容在服务器和客户端之间不可避免地不同(例如,时间戳)。在这种情况下,我们可以通过向元素添加 suppressHydrationWarning = {true} 来静默该警报。 如果它不是文本元素,它不会尝试修补它,因此它可能会保持不一致直到未来的更新。 如果您需要特意在服务器和客户端上提供不同的内容,可以执行两遍渲染。客户端上的组件可以读取像 this.state.isClient 这样的状态变量,它将在 componentDidMount() 中设置为 true。 初始渲染过程将与服务器相同,避免不一致,但在 hydrate 后会同步进行额外的渲染过程。 注意:这种方法会使组件变慢,因为它们需要渲染两次,所以请谨慎使用。注意在 React 中,unmountComponentAtNode 已被 root.unmount() 取代。它会从 DOM 中移除已挂载的 React 组件,并清理其事件处理程序和状态。 如果没有组件挂载到该容器,它什么也不做。如果没有组件被卸载,返回 true;如果没有组件可卸载,返回 false。 findDOMNode()注意:findDOMNode 是一个用于访问底层 DOM 节点的应急方案 (escape hatch)。在大多数情况下不鼓励使用此应急方案,因为它破坏了组件的抽象。它在 StrictMode 中已被弃用。findDOMNode(component)如果此组件已挂载到 DOM,则此方法返回相应的原生浏览器 DOM 元素。此方法对于从 DOM 读取值(例如表单字段值)和执行 DOM 测量很有用。在大多数情况下,您可以附加一个对 DOM 节点的引用,并避免使用 findDOMNode。 当一个组件返回 null 或 false 时,findDOMNode 返回 null。当一个组件被渲染成字符串时,findDOMNode 返回包含该值的文本 DOM 节点。如果组件返回一个带有多个子元素的 fragment,findDOMNode 将返回与第一个非空子元素对应的 DOM 节点。 注意 findDOMNode 仅适用于已挂载的组件(即已放置在 DOM 中的组件)。如果您尝试在一个尚未挂载的组件上调用此方法(例如,在尚未创建的组件的 render() 中调用 findDOMNode()),将会抛出异常。 findDOMNode 不能在函数组件中使用。 DOM 元素React 实现了一个与浏览器无关的 DOM 系统,以实现性能和跨浏览器兼容性。我们借此机会清理了浏览器 DOM 实现中的一些粗糙边缘。 在 React 中,所有的 DOM 属性和特性(包括事件处理程序)都必须是驼峰式命名 (camelcase)。例如,HTML 的 tabindex 属性在 React 中对应于 tabIndex 属性。 例外是 aria-* 和 data-* 属性,它们必须是小写的。例如,你可以将 aria 标签写成 aria 标签。 属性差异有几个属性在 React 和 HTML 之间的工作方式不同 checkedchecked 属性受类型为 checkbox 或 radio 的 <input> 组件支持。它对于制造受控组件很有用。您可以使用它来确定组件是否被选中。 defaultChecked 是其非受控的对应项,它决定了组件在首次挂载时是否被选中。 className要指定 CSS 类,请使用 className 属性。它适用于所有常规的 DOM 和 SVG 元素,如 <div>、<a> 等。 如果您将 React 与 Web Components 一起使用(不常见),请改用 class 属性。 dangerouslySetInnerHTMLDangerouslySetInnerHTML 是 React 中替代浏览器 DOM 中使用 innerHTML 的方法。配置 HTML 代码是有风险的,因为它很容易让用户遭受跨站脚本攻击(XSS)。 因此,您可以直接从 React 设置 HTML,但必须输入 dangerouslySetInnerHTML 并传递一个带有 __html 键的对象,以提醒自己这是危险的。 例如React 元素使用 htmlFor,因为 for 是 JavaScript 中的保留字。 onChangeonChange 事件的行为符合预期;每当表单字段更改时,该事件就会触发。 我们特意不使用现有的浏览器行为,因为 change 的行为是独特的,而 React 依赖此事件来实时处理用户输入。 selected如果您想将 <option> 标记为已选中,请在 <select> 的 value 中引用该选项的值。有关详细说明,请参阅“Select 标签”。 注意 在大多数情况下,类名指的是在外部 CSS 样式表中定义的类。样式在 React 应用中用于在渲染时添加计算出的样式。style 属性接受一个带有驼峰式命名属性的 JavaScript 对象,而不是 CSS 字符串。 这符合 DOM 风格的 JavaScript 属性,效率更高,并避免了 XSS 安全漏洞。 例如 请注意:样式不会自动添加前缀。为了支持旧版浏览器,我们需要提供样式属性样式键是驼峰式的,以对应从 JS 内部访问 DOM 节点上的属性。供应商前缀 MS 以大写字母开头。 React 会自动为某些内联数字样式属性添加“px”后缀。如果您想使用“px”以外的单位,请将值指定为带有所需单位的字符串。 例如 然而,并非所有样式属性都会转换为像素字符串。 抑制可编辑内容警报如果一个元素的子元素被标记为 contentEditable,会出现警告,因为它将无法工作。该属性可以抑制此警告。 抑制警告如果我们使用服务器端 React 渲染,当服务器和客户端渲染出不同内容时,会出现警告。然而,在极少数情况下,很难保证完全匹配。例如,时间戳在服务器或客户端上预计会有所不同。 如果将 suppression warning 设置为 true,React 将不会警告元素属性和内容之间的不匹配。 它只在一层深度上起作用,旨在作为一种应急方案使用。 值value 属性由 <input>、<select> 和 <textarea> 组件设计。您可以使用它来设置组件的值。 它对于制造受控组件很有用。defaultValue 与 unchecked 类似,用于在组件挂载时设置其值。 所有支持的 HTML 属性支持任何自定义和标准的 DOM 属性。 React 在 DOM 中提供了一个以 JavaScript 为中心的 API。而且 React 组件通常包含自定义和与 DOM 相关的 props,然后 React 使用与 DOM API 相同的驼峰命名约定 下一个主题React 中的单元测试 |
我们请求您订阅我们的新闻通讯以获取最新更新。