React Native 有“虚拟 DOM”吗?

Posted

技术标签:

【中文标题】React Native 有“虚拟 DOM”吗?【英文标题】:Does React Native have a 'Virtual DOM'? 【发布时间】:2017-06-07 20:59:28 【问题描述】:

来自ReactJS wiki关于虚拟DOM的页面:

React 创建一个内存数据结构缓存,计算 产生的差异,然后更新浏览器显示的 DOM 有效率的。这允许程序员编写代码,就好像 每次更改都会呈现整个页面,而仅 React 库 渲染实际发生变化的子组件。

换句话说,Virtual DOM 允许我们通过避免直接操作 DOM 来提高性能。

但是React Native 呢?

我们知道理论上在其他平台上存在原生视图和 UI 组件。 DOM 本身并没有什么。 所以我们可以说 React Native 有“虚拟 DOM”还是我们在谈论其他东西?

例如,Weex 规范中有一个section,它描述了直接使用 DOM-tree 的方法。我的假设是,我们可能会认为 React Native 也应该有某种 DOM 树以及“虚拟 DOM”抽象层,这是 React 本身的主要思想。

所以我的问题是:

React Native 是否有某种“虚拟 DOM”(或其表示形式),如果有,如何将这种“虚拟 DOM”移植到各种平台?

更新:

这个问题的目的是阐明 React Native 如何管理原生 UI 组件的渲染。有没有具体的做法,如果有,官方是怎么称呼的?

更新 2:

This article 描述了名为Fiber 的新 React 架构,看起来就像这个问题的答案。

【问题讨论】:

这里的反对票是怎么回事? @JohnWeisz 似乎人们认为这个问题太宽泛了,但是,我不会这么说。只是想阐明文档中实际遗漏的内容。 事实上,过于宽泛可能证明一个接近的投票是合理的,而不是一个反对票。 你引用的 react native 的链接清楚地表明它的原生部分是为了实现移动 java/swift/ios 组件,而不是 dom。 “使用 React Native,您无需构建“移动 Web 应用程序”、“html5 应用程序”或“混合应用程序”。您构建的是真正的移动应用程序......”。这里没有 100% 肯定的声明,但实际上涉及 dom 的可能性很小,至少对于插入的本机组件的主要部分而言。 @Sebas medium.com/@jiyinyiyong/virtual-dom-is-the-new-ir-67839bcb5c71 是我产生这种想法的原因。刚刚决定确定真相。 【参考方案1】:

简而言之

嗯.. 本质上,是的,就像 Reactjs 的虚拟 DOM 一样,React-Native 创建一个树层次结构来定义初始布局,并在每次布局更改时创建该树的差异以优化渲染。除了 React-Native 通过几个架构层来管理 UI 更新之外,这些架构层最终会转换视图应该如何呈现,同时尝试将更改优化到最低限度,以提供尽可能快的呈现。

更详细的解释

为了了解 react native 如何在后台创建视图,您需要了解基础知识,为此,我宁愿从头开始

1.Yoga 布局引擎

Yoga 是一个用 C 语言编写的跨平台布局引擎,它通过绑定到原生视图来实现 Flexbox(Java android Views / Objective-C iOS UIKit)

React-Native 中各种视图、文本和图像的所有布局计算都是通过 Yoga 完成的,这基本上是我们的视图显示在屏幕上之前的最后一步

2。影子树/影子节点

当 react-native 发送命令来渲染布局时,一组影子节点被组装起来构建影子树,它代表了布局的可变原生端(即:用相应的原生语言编写,Java for Android 和Objective-C for iOS)然后被翻译成屏幕上的实际视图(使用 Yoga)。

3。视图管理器

ViewManger 是一个接口,它知道如何将从 javascript 发送的视图类型转换为其本机 UI 组件。 ViewManager 知道如何创建影子节点、本地视图节点和更新视图。 在 React-Native 框架中,有很多 ViewManager 可以使用原生组件。 例如,如果有一天您想创建一个新的自定义视图并将其添加到 react-native,则该视图必须实现 ViewManager 接口

4。界面管理器

UIManager 是拼图的最后一块,或者实际上是第一块。 JavaScript JSX 声明式命令作为命令式命令发送到本机,这些命令告诉 React-Native 如何布局视图,逐步迭代。 因此,作为第一次渲染,UIManager 将调度命令以创建必要的视图,并将随着应用程序的 UI 随时间变化而继续发送更新差异。

所以 React-Native 基本上还是利用了 Reactjs 的能力,计算出之前和当前渲染表示的差异,并相应地将事件分派给 UIManager

要更深入地了解该过程,我推荐以下来自弗罗茨瓦夫 React-Native EU 2017 会议的 Emil Sjölander presentation

【讨论】:

【参考方案2】:

This article 描述了名为Fiber 的新 React 架构。这似乎是关于 React Native 中正在发生的事情的正确答案,或者至少是 React Native 将在不久的将来尝试实现的目标。

DOM 只是 React 可以渲染到的渲染环境之一, 其他主要目标是通过 React 实现的原生 iOS 和 Android 视图 本国的。 (这就是为什么“虚拟 DOM”有点用词不当。)

之所以能支持这么多目标,是因为 React 是设计的 因此对账和渲染是不同的阶段。这 reconciler 负责计算树的哪些部分具有 改变了;渲染器然后使用该信息来实际更新 渲染的应用程序。

这种分离意味着 React DOM 和 React Native 可以使用它们的 拥有自己的渲染器,同时共享相同的协调器,由 React 提供 核心。

Fiber 重新实现了协调器。

【讨论】:

【参考方案3】:

这里有一个过度简化:ReactJS 输出可以呈现给浏览器的 DOM。如您所知,虚拟 DOM 帮助 ReactJS 有效地跟踪变化的增量。对于 iOS 的 React Native,最终它会输出 UIKit 代码。与 React Native for Android 相同,但不是输出 DOM 或 UI Kit,而是使用 Android SDK 创建输出。所以虚拟 DOM 只是一个中间步骤。它可以被认为是内部数据结构的组合,用于保存描述在何处呈现按钮和文本框的数据,当您单击按钮时会发生什么等,以及跟踪更改的有效算法。相同的代码可用于所有平台。只有最后一步不同。根据平台的不同,它具有生成 DOM、UIKit 代码或任何名称的 Android UI lib 的代码。

【讨论】:

【参考方案4】:

我不知道这是否是您问题的答案,但我在 the official React docs: 中找到了这个

React 构建并维护渲染 UI 的内部表示。它包括您从组件返回的 React 元素。这种表示可以让 React 避免创建 DOM 节点和不必要地访问现有节点,因为这可能比对 JavaScript 对象的操作要慢。有时它被称为“虚拟 DOM”,但它在 React Native 上的工作方式相同。

所以我会说是的,它管理的内部表示与 React.js 中使用的表示非常相似。然后我猜它使用 Javascript API 来呈现原生视图,就像 the article you read 建议的那样。

编辑 Sebas 在评论中提供的 This post 也很有趣,因为 React(和 React Native)团队的成员说:

React Native 表明,ReactJS 一直更关注“零 DOM”而不是“虚拟 DOM”(与流行的看法相反)。

似乎所谓的“React 虚拟 DOM”更接近于可以映射到各种技术的元素的内部结构/表示,而不是 HTML DOM。

【讨论】:

以上是关于React Native 有“虚拟 DOM”吗?的主要内容,如果未能解决你的问题,请参考以下文章

React Native - 0序言

虚拟DOM知多少

react Native如何实现跨平台

React diff策略

[react] 你知道Virtual DOM的工作原理吗?

JS487- 虚拟 DOM 到底是什么?(建议收藏)