热门React D3库及性能优化指南
在数据可视化领域,使用基于D3和React的现成库可以显著提高开发效率。本文将介绍几种流行的React D3库,包括它们的设置、实现、优缺点以及成本,并分享一些性能优化的技巧。
1. 流行的React D3库
1.1 Visx
Visx是第二受欢迎的库,Airbnb团队在这个库上投入了很多精力,它具有良好的视觉吸引力和支持。
1.1.1 设置
使用以下命令安装所需的模块:
yarn add @visx/mock-data @visx/group @visx/shape @visx/scale
1.1.2 实现
以下是一个简单的柱状图示例:
// src/component/SimpleBarGraph/SimpleBarGraph.tsx
import React from 'react'
import { letterFrequency } from '@visx/mock-data'
import { Group } from '@visx/group'
import { Bar } from '@visx/shape'
import { scaleLinear, scaleBand } from '@visx/scale'
const uuid = require('react-uuid')
const data = letterFrequency
const width = 500
const height = 500
const margin = { top: 20, bottom: 20, left: 20, right: 20 }
const xMax = width - margin.left - margin.right
const yMax = height - margin.top - margin.bottom
const x = (d: { letter: any }) => d.letter
const y = (d: { frequency: React.Key }) => +d.frequency * 100
const xScale = scaleBand({
range: [0, xMax],
round: true,
domain: data.map(x),
padding: 0.4,
})
const yScale = scaleLinear({
range: [yMax, 0],
round: true,
domain: [0, Math.max(...data.map(y))],
})
const compose = (scale, accessor) => d => scale(accessor(d))
const xPoint = compose(xScale, x)
const yPoint = compose(yScale, y)
function SimpleBarGraph() {
return (
<svg width={width} height={height}>
{data.map((d, i) => {
const barHeight = yMax - yPoint(d)
return (
<Group key={`bar-${uuid()}`}>
<Bar
x={xPoint(d)}
y={yMax - barHeight}
height={barHeight}
width={xScale.bandwidth()}
fill="grey"
/>
</Group>
)
})}
</svg>
)
}
export default SimpleBarGraph
在
App.tsx
中引入组件:
<SimpleBarGraph />
1.1.3 成本
解析后的大小为42KB,相对较小。
1.1.4 优缺点
- 优点 :占用空间小,由低级组件组成,适合功能接近需求的最终产品,内置模拟数据,方便前端开发。
- 缺点 :组件被拆分为小的低级组件,开发者需要将它们组合起来,有一定的学习曲线,对于简单图表来说可能过于复杂。
1.2 Victory
Victory是用于模块化图表和数据可视化的React.js组件。
1.2.1 设置
使用以下命令安装:
yarn add victory
1.2.2 实现
以下是一个简单的饼图示例:
// src/component/SimplePie/SimplePie.tsx
import React from 'react'
import { VictoryPie } from 'victory'
const SimplePie = () => {
return (
<div className="SimplePie">
<VictoryPie
data={[
{ x: 'Cats', y: 35 },
{ x: 'Dogs', y: 40 },
{ x: 'Birds', y: 55 }
]}
/>
</div>
)
}
export default SimplePie
1.2.3 成本
解析后的成本为164KB。
1.2.4 优缺点
- 优点 :易于实现,示例简单,有令人印象深刻的画廊示例,拥有大量的追随者、粉丝和支持者。
- 缺点 :图表种类不如其他一些库多,并且存在较多未解决的bug。
1.3 Nivo
Nivo提供了丰富的基于D3和Reactjs的可视化组件。
1.3.1 设置
使用以下命令安装核心库和所需模块:
yarn add @nivo/core @nivo/calendar
1.3.2 实现
以下是一个日历图表的示例:
// src/component/SimpleCalendarChart/SimpleCalendarChart.tsx
import React from 'react'
import { ResponsiveCalendar } from '@nivo/calendar'
const SimpleCalendarChart = (props: { data: { day: string; value: number }[] }) => {
return (
<div style={{ width: 800, height: 500 }}>
<ResponsiveCalendar
data={props.data}
from="2019-01-01"
to="2021-12-31"
emptyColor="#eeeeee"
colors={['#61cdbb', '#97e3d5', '#e8c1a0', '#f47560']}
margin={{ top: 40, right: 40, bottom: 40, left: 40 }}
yearSpacing={40}
monthBorderColor="#ffffff"
dayBorderWidth={2}
dayBorderColor="#ffffff"
legends={[
{
anchor: 'bottom-right',
direction: 'row',
translateY: 36,
itemCount: 4,
itemWidth: 42,
itemHeight: 36,
itemsSpacing: 14,
itemDirection: 'right-to-left',
},
]}
/>
</div>
)
}
export default SimpleCalendarChart
在
App.tsx
中获取数据并传递给组件:
import React from 'react'
import './App.scss'
import { useRecoilValue } from 'recoil'
import SimpleCalendarChart from './components/SimpleCalendarChart/SimpleCalendarChart'
import { getCalendarData } from './recoil/selectors/calendarDataSelectors'
function App() {
const data = useRecoilValue(getCalendarData) as { day: string, value: number }[]
return (
<div className="App">
<header className="App-header">
<SimpleCalendarChart data={data} />
</header>
</div>
)
}
export default App
1.3.3 成本
使用一个模块需要核心库,成本为241KB,包含React-spring、D3、lodash等库。
1.3.4 优缺点
- 优点 :提供独特的图表选择,外观美观,易于实现,具有服务器端渲染(SSR)API,适合处理大型数据集。
- 缺点 :示例不够直观,使用文档中的示例时可能无法渲染,需要设置包装容器的宽度和高度。
1.4 React-vis
React-vis是Uber创建的可组合图表库。
1.4.1 设置
使用以下命令安装库和类型:
yarn add react-vis @types/react-vis
1.4.2 实现
以下是一个简单的折线图示例:
// src/component/SimpleReactVizChart/SimpleReactVizChart.tsx
import React from 'react'
import './BasicRadarChart.scss'
import '../../../node_modules/react-vis/dist/style.css'
import { XYPlot, LineSeries, XAxis, YAxis, HorizontalGridLines, VerticalGridLines } from 'react-vis'
const SimpleReactVizChart = () => {
return (
<>
<div className="App">
<XYPlot height={300} width={300}>
<LineSeries
data={[
{ x: 0, y: 8 },
{ x: 1, y: 5 },
{ x: 2, y: 4 },
{ x: 3, y: 9 },
{ x: 4, y: 1 },
{ x: 5, y: 7 },
{ x: 6, y: 6 },
{ x: 7, y: 3 },
{ x: 8, y: 2 },
{ x: 9, y: 0 },
]}
/>
<VerticalGridLines />
<HorizontalGridLines />
<XAxis />
<YAxis />
</XYPlot>
</div>
</>
)
}
export default SimpleReactVizChart
1.4.3 成本
未解析大小为635KB,解析后为316KB。
1.4.4 优缺点
- 优点 :易于实现,提供大量简单和自定义的图表,自带CSS文件帮助样式组件。
- 缺点 :库的一致性较差,体积较大,存在较多未解决的bug,需要进行架构重构。
1.5 各库对比
| 库名 | Stars数量 | 贡献者数量 | 开源问题数量 | 解析后大小 | 优点 | 缺点 |
|---|---|---|---|---|---|---|
| Visx | 与Victory接近 | - | - | 42KB | 小体积,低级别组件,内置模拟数据 | 学习曲线,简单图表使用复杂 |
| Victory | 与Visx接近 | 约为Visx两倍 | 约为Visx两倍 | 164KB | 易于实现,示例丰富 | 图表种类少,bug多 |
| Nivo | - | - | - | 241KB | 独特图表,支持SSR | 示例不直观,需设置容器尺寸 |
| React-vis | - | 116 | 277 | 316KB | 易于实现,图表选择多,自带CSS | 一致性差,体积大,bug多 |
2. 性能优化技巧
2.1 数据加载
优化数据传输可以显著减少图表加载时间。只传输所需的指标,避免加载整个数据集。例如,在绘制日历图表时,只使用2019 - 2021年的数据,而不是包含2018年的完整数据集。
2.2 安装模块而非全局导入
对于D3(版本4及以上)和其他许多库,可以导入特定模块而不是整个库,从而显著减少应用程序的包大小。以下是具体步骤:
1. 安装
cra-bundle-analyzer
作为开发依赖:
yarn add --dev cra-bundle-analyzer
- 运行分析工具:
yarn analyzer
- 创建一个简单的React D3代码,分别使用全局导入和模块导入D3,并比较包大小。
// 全局导入
import * as d3 from 'd3'
// 模块导入
import { select } from 'd3-selection'
2.3 其他性能优化技巧
- 服务器端渲染(SSR) :在服务器端生成HTML,减少客户端渲染时间。
- Tree shaking :移除未使用的代码,减小包大小。
- 仅在需要时更新DOM :避免不必要的DOM操作,提高性能。
- 使用CSV代替JSON :CSV文件通常比JSON文件更小,传输速度更快。
- 优化CRA :使用预渲染、预取和预缓存等技术。
-
使用
useCallback记忆函数 :避免不必要的函数重新创建。
综上所述,选择合适的React D3库可以提高开发效率,但需要根据具体需求权衡其优缺点。同时,采用性能优化技巧可以显著提升应用程序的性能。
3. 性能优化操作实例
3.1 数据加载优化实例
接下来通过具体例子展示如何优化数据加载。假设我们要创建一个股票价格可视化图表,原始数据包含了多只股票多年的详细信息,但我们只需要某一只股票近一年的数据。
操作步骤
- 数据筛选 :在后端对数据进行筛选,只返回所需的股票近一年的数据。以下是一个简单的Node.js示例:
const express = require('express');
const app = express();
const allStockData = require('./allStockData.json');
app.get('/stockData', (req, res) => {
const targetStock = 'ABC';
const oneYearAgo = new Date();
oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);
const filteredData = allStockData.filter(item => {
return item.stockName === targetStock && new Date(item.date) >= oneYearAgo;
});
res.json(filteredData);
});
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
-
前端获取数据
:在前端使用
fetch请求筛选后的数据:
async function getStockData() {
try {
const response = await fetch('/stockData');
const data = await response.json();
// 使用数据绘制图表
drawChart(data);
} catch (error) {
console.error('Error fetching data:', error);
}
}
function drawChart(data) {
// 绘制图表的代码
}
getStockData();
3.2 安装模块而非全局导入实例
继续以之前创建的
Rectangle
组件为例,展示如何通过导入特定模块来减小包大小。
操作步骤
-
创建组件
:使用
npx generate-react-cli创建Rectangle组件:
npx generate-react-cli component Rectangle --type=d3
-
安装依赖
:安装全局D3库和
d3-selection模块:
yarn add d3-selection @types/d3-selection
yarn add d3 @types/d3
- 全局导入示例 :
// src/component/Rectangle/Rectangle.tsx
import React, { useEffect, RefObject } from 'react';
import * as d3 from 'd3';
const Rectangle = () => {
const ref: RefObject<HTMLDivElement> = React.createRef();
useEffect(() => {
draw();
});
const draw = () => {
d3.select(ref.current).append('p').text('Hello World');
d3.select('svg')
.append('g')
.attr('transform', 'translate(250, 0)')
.append('rect').attr('width', 500)
.attr('height', 500)
.attr('fill', 'tomato');
};
return (
<div className="Rectangle" ref={ref}>
<svg width="500" height="500">
<g transform="translate(0, 0)">
<rect width="500" height="500" fill="green" />
</g>
</svg>
</div>
);
};
export default Rectangle;
- 模块导入示例 :
// src/component/Rectangle/Rectangle.tsx
import React, { useEffect, RefObject } from 'react';
import { select } from 'd3-selection';
const Rectangle = () => {
const ref: RefObject<HTMLDivElement> = React.createRef();
useEffect(() => {
draw();
});
const draw = () => {
select(ref.current).append('p').text('Hello World');
select('svg')
.append('g')
.attr('transform', 'translate(250, 0)')
.append('rect').attr('width', 500)
.attr('height', 500)
.attr('fill', 'tomato');
};
return (
<div className="Rectangle" ref={ref}>
<svg width="500" height="500">
<g transform="translate(0, 0)">
<rect width="500" height="500" fill="green" />
</g>
</svg>
</div>
);
};
export default Rectangle;
-
比较包大小
:使用
cra-bundle-analyzer分析包大小:
yarn add --dev cra-bundle-analyzer
yarn analyzer
通过对比可以发现,使用模块导入时D3的解析大小显著减小。
2.3 性能优化技巧总结
| 优化技巧 | 说明 | 操作步骤 |
|---|---|---|
| 数据加载优化 | 只传输所需的指标,避免加载整个数据集 | 后端筛选数据,前端请求筛选后的数据 |
| 安装模块而非全局导入 | 导入特定模块而非整个库,减小包大小 | 安装分析工具,对比全局导入和模块导入的包大小 |
| 服务器端渲染(SSR) | 在服务器端生成HTML,减少客户端渲染时间 | 使用支持SSR的框架,如Next.js |
| Tree shaking | 移除未使用的代码,减小包大小 | 使用支持Tree shaking的打包工具,如Webpack |
| 仅在需要时更新DOM | 避免不必要的DOM操作,提高性能 |
使用React的
shouldComponentUpdate
或
React.memo
|
| 使用CSV代替JSON | CSV文件通常比JSON文件更小,传输速度更快 |
使用CSV解析库,如
csv-parser
|
| 优化CRA | 使用预渲染、预取和预缓存等技术 |
使用
react-scripts
的相关配置
|
使用
useCallback
记忆函数
| 避免不必要的函数重新创建 |
在函数定义时使用
useCallback
|
4. 性能优化流程
graph LR
A[开始] --> B[数据加载优化]
B --> C[安装模块而非全局导入]
C --> D[服务器端渲染]
D --> E[Tree shaking]
E --> F[仅在需要时更新DOM]
F --> G[使用CSV代替JSON]
G --> H[优化CRA]
H --> I[使用useCallback记忆函数]
I --> J[结束]
通过以上的性能优化技巧和操作实例,我们可以在使用React D3库进行数据可视化开发时,提高应用程序的性能和用户体验。在选择库时,根据具体需求权衡各库的优缺点,同时结合性能优化技巧,打造高效、稳定的数据可视化应用。
超级会员免费看
63

被折叠的 条评论
为什么被折叠?



