将 React、D3 及其生态系统相互融合

React 和 D3.js 是能帮助我们处理页面元素及其所带来的挑战的伟大工具。它们当然可以一起工作,我们被赋予了在两个工具的界限之间去选择的能力。

—— 本文作者 马克思.西亚斯

自从2011年问世以来,D3.js 已经成为在网络上建立复杂数据可视化界面的实际标准。React 作为一个创建基于组件的用户界面方面的选择的库也在迅速成熟。

React 和 D3 是两个非常优秀的工具,它们的目标有时候会重叠。它们都会控制用户界面元素,但是用的方法不一样。我们怎么样可以让它们一起工作呢,这要根据你的当前项目选择其各自最大的优点。

本文中,我们能够看到怎么样在创建需要用到 D3 的强大的表格体系的 React 项目。我们会发现不同的技术还有怎么在你的主要的工作以及副项目中选择符合你需求的最好的库。

D3 和 DOM

D3.js 中的 D3 代表数据驱动文档(data-driven documents)。D3.js 是一个底层库,它提供了创建交互可视化所必要的基石。在可视化效果的样式和行为方面,它根据如 SVG,HTML,图层,和 CSS 的 web 标准,使用了大量的 API 和近乎无限的控制器,组装成一个前后端工具箱。它还提供了一些数学函数有助于用户计算复杂的 SVG 路径。

它是如何工作的?

简而言之,D3.js 加载数据并将其附加到了 DOM 。然后,它绑定那些数据到 DOM 元素并转换那些元素,若有必要则在各个状态之间转换。

D3.js selections 与  jQuery objects 类似,都帮助我们处理了 SVG 的复杂性。它处理 HTML DOM 元素的方式可以与 jQuery 处理的方式相媲美。在链式 API 以及将 DOM 作为数据存储的用法上,这两个库也有相似之处。

数据联合

数据联合,就像在 Mike Bostocks 的文章“ 对联合的思考 ”中解释的,是 D3 使用 selection 连接数据到 DOM 元素的过程。

数据联合帮助我们匹配我们提供给已经创建的元素的数据,添加缺失的项,删除不再需要的元素。它们使用 D3.js selections ,当与数据结合时,它将选择的元素分为3个不同组:需要创建的元素(加入组),需要更新的元素(更新组),需要删除的元素(退出组)。

实际上,一个具有两个数组的 JavaScript 对象相当于一个数据联合。通过调用 selection 的加入和退出函数,我们可以在加入组和退出组 触发操作 ,然而在最新版本的 D3.js ,我们可以直接在更新组操作。

就像 Bostock 描述的一样,使用数据联合,“你可以实现实时数据可视化,允许交互探索,数据集之间的平滑转换”。他们实际上是一种 diff 算法,与 React 管理子元素渲染的方式相似,正如我们将在下面章节中看到的。

D3库

D3社区没有找到标准方法通过D3代码来创建组件,这经常被需要,因为D3.js非常低级。我们能说有几乎与基于D3库一样多的封装模式,尽管我将它们 - 通过它们的API - 分为四组:面向对象的,声明性的,功能性的和链式的(或类似D3)。

我对 D3.js生态系统 做了一些研究,并选择了一个小型的高质量子集。它们是D3.js的第四版本最新库,具有良好的测试覆盖率。它们在API的类型和抽象的粒度上有所不同。

Plottable

Plottable 是一个流行的面向对象图表库,它的特点是低粒度;所以,我们需要设置坐标轴、比例和手动绘制来形成图表。你可以 在这里 看到一个例子。

Billboard

Billboard 是一个著名的 C3.js库 的分支,更新了D3.js的第四版本。旨在为这个经典的库提供连续性。它是使用ECMAScript 6和新的现代工具(如Webpack)编写的。它的API基于传递给图表的配置对象,因此我们可以说它是一个声明性API。

Vega

Vega 把声明路径进一步扩展, 将配置从JavaScript对象转化成SJON文件。旨在为实现一个可视化语法,灵感源于 图形语法 ,一本由Leland Wilkinson编写的书,将数据可视化的结构块形式化,这是D3.js的灵感来源。您可以使用其 编辑器 ,选择其中一个示例作为起点。

D3FC

D3FC 使用D3. js和定制构建块可以帮助您在SVG和canvas中创建强大的交互式图表。 它的特色在于提供函数式、低粒度的接口和大量的D3. js代码,虽然功能强大,但可能需要一些学习过程。 查看 它的例子

Britecharts

Britecharts —— 使用Eventbrite创建的一个库,我是其中的核心贡献者——使用了可重用的图表API,这是一种封装模式,由Mike Bostock在他的文章“ 面向可重用图表 ”中推广,并在 NVD3 等其他库中使用。 Britecharts创建了一个高级抽象,使得创建图表变得容易,同时保持了内部的低复杂性,允许D3开发人员定制Britecharts供他们使用。 我们花了很多时间构建一个完善的UI和许多实用的 演示

通过他们的API来总结这些库,我们可以这样表示:

React 和 DOM

React是一个JavaScript库,它帮助我们通过组合组件来构建用户界面。 这些组件跟踪它们的状态,并传递属性来有效地重新呈现它们自己,从而优化应用程序的性能。

它是如何工作的呢?

虚拟DOM ,是DOM当前状态的一种表示,它是支持React的重渲染优化的技术。 该库使用一个复杂的diff算法来理解当条件发生变化时,应用程序的哪些部分需要重新渲染。 这个diff算法被称为“ 和解算法 ”。

动态子组件

当渲染包含项目列表的组件时,开发人员需要使用附加到子组件的唯一“键”属性。 这个值帮助diff算法弄清楚当新数据——或者在React世界中成为状态——被传递给组件时,是否需要重新呈现该项。 和解算法检查键的值,看是否需要添加或删除该项。 在了解了D3之后,有没有感觉这和D3.js的数据连接很相似 ?

从版本0.14起,React也使渲染器保持在一个单独的模块中。 通过这种方式,我们可以 在不同的媒介中 使用相同的组件,例如本机应用程序( React Native )、虚拟现实( React VR )和DOM( react-dom )。 这种灵活性与D3的方式相似,D3.js的 代码可以在不同的上下文中呈现,比如SVG和canvas。

React And D3.js

React和D3共同的目标是帮助我们以高度优化的方式处理DOM及其复杂性。它们还共享对纯函数的偏好 - 对于给定的输入,它总是返回相同的输出而不会产生副作用的代码 - 以及无状态组件。

但是,关于DOM的共同关注使得这两个自用的库在确定哪个是渲染和动画用户界面元素时发生冲突。我们将看到解决这一争议的不同方法,并且没有简单的答案。但是,我们可以建立一个硬性规则:它们永远不应该共享DOM控制。那将是一场灾难。

途径

当集成React和D3.js时,我们可以在不同的级别上进行,更多地依赖于D3.js方面或React方面。让我们看看我们的四个主要选择。

D3.js Within React

我们可以遵循的第一种方法是尽可能多地为D3代码提供DOM控制。它使用React组件来渲染一个空的SVG元素,该元素用作数据可视化的根元素。然后,它使用componentDidUpdate生命周期方法,使用该根元素,使用我们将在vanilla JavaScript场景中使用的D3.js代码创建图表。我们还可以通过使shouldComponentUpdate方法始终返回false来阻止任何进一步的组件更新。

评估这种方法,我们认识到它提供了一些好处和缺点。在这些优点中,这是一个简单的解决方案,大部分时间都可以正常工作。当您将现有代码移植到React中,或者当您使用已经在其他地方工作的D3.js图表时,它也是最自然的解决方案。

在缺点方面,在React组件中混合使用React代码和D3.js代码可能会被视为有点严重,包含太多依赖项并使该文件太长而无法被视为质量代码。此外,这种实现根本不会感觉到React-idiomatic。最后,因为React渲染服务器不调用componentDidUpdate方法,所以我们无法在初始HTML中提供图表的渲染版本。

React Faux DOM

由Oliver Caldwell实现, React Faux DOM   “是一种使用现有D3工具的方式,但在 React ethos中 通过React渲染它。”它使用虚拟的DOM实现来让D3.js认为它正在处理真正的DOM。 这样,我们保留React DOM树的同时可以使用D3.js。

这种方式的一个优点是它允许您使用大多数D3.js的API,从而可以轻松地 集成 已构建的D3.js代码。 它还允许服务器端呈现。 这种策略的一个缺点是性能较差,因为我们在React的虚拟DOM之前放置了另一个虚拟的DOM实现,两次虚拟化DOM。 此问题限制了它对中小型数据可视化的使用。

生命周期封装

由Nicolas Hery提出的基于类的React组件中的生命周期这种方法,优雅地包装了D3.JS图表的创建、更新和删除,在React和D3.js代码之间建立了一个清晰的边界。

D3Line如下:

通过一个简单的API(创建、更新和删除)与D3.js为基础的图表实例通信这种方式产生一个轻量级的反作用组件,通过期望的回调函数向下传递。

通过使用外表来隐藏图表的实现细节这种策略促进结构分离。这种方式可以封装任何图形,并且易于生成相应的对外接口。另一个好处是,它很容易与任何已经编写的D3.js代码集成,允许我们使用D3.js的优秀转换。这种方法的主要缺点 是不可能实现 服务器端的渲染。

我来评几句
登录后评论

已发表评论数()

相关站点

热门文章