关于 recharts
Recharts 是基于 D3 的 React 图表库,面向构建声明式、可组合数据可视化的开发者。它提供多种图表组件、响应式尺寸设置,以及交互和无障碍支持。
主要功能
- 01可组合的 React 图表组件
- 02折线、柱形、面积、饼图等类型
- 03响应式与固定尺寸
- 04自定义提示框、标签和形状
- 05图表交互与同步
- 06支持键盘和屏幕阅读器
适用场景
- 01在 React 界面中构建数据图表
- 02在单个可视化中组合多种图表
- 03创建响应式仪表板
- 04添加交互式无障碍图表
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ andy-spike/ skills --skill recharts安装后在 Claude Code 中输入/recharts确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api_reference.mdbest_practices.mdexamples.md详细介绍
Recharts
基于 D3 构建的 React 图表库,用于组合式、声明式数据可视化。
快速开始
1. 安装 Recharts
npm install recharts
2. 基本图表结构
所有 Recharts 图表都遵循相同的模式:
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
const data = [
{ name: 'Jan', sales: 4000, profit: 2400 },
{ name: 'Feb', sales: 3000, profit: 1398 },
{ name: 'Mar', sales: 2000, profit: 9800 },
];
<ResponsiveContainer width="100%" height={300}>
<LineChart data={data}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Legend />
<Line type="monotone" dataKey="sales" stroke="#8884d8" />
<Line type="monotone" dataKey="profit" stroke="#82ca9d" />
</LineChart>
</ResponsiveContainer>
核心概念
数据格式
Recharts 要求数据采用对象数组的形式。每个对象代表一个数据点:
const data = [
{ month: 'Jan', revenue: 4000, expenses: 2400 },
{ month: 'Feb', revenue: 3000, expenses: 1398 },
];
使用 dataKey 属性将对象属性映射到图表组件:
dataKey="revenue"- 映射到 revenue 属性dataKey={(entry) => entry.revenue - entry.expenses}- 用于计算值的函数
组件组合
图表通过嵌套专用组件构建:
尺寸:使用 responsive 属性(v3.3+)、ResponsiveContainer 封装组件,或直接设置 width/height
图表类型(选择一种):
LineChart- 折线图和面积图BarChart- 条形图和柱状图AreaChart- 堆叠面积图和填充面积图PieChart- 饼图和环形图ScatterChart- 散点图和气泡图ComposedChart- 混合图表类型RadarChart- 雷达图/蜘蛛网图RadialBarChart- 环形条形图
常见子组件:
XAxis/YAxis- 轴配置CartesianGrid- 网格线Tooltip- 悬停信息Legend- 数据系列标识Line/Bar/Area/Pie- 数据系列可视化
各类图表模式
折线图
<LineChart data={data}>
<XAxis dataKey="name" />
<YAxis />
<CartesianGrid strokeDasharray="3 3" />
<Tooltip />
<Legend />
<Line type="monotone" dataKey="value" stroke="#8884d8" strokeWidth={2} dot={{ r: 4 }} />
</LineChart>
关键属性:
type:"monotone"(平滑)、"linear"、"step"、"natural"stroke:线条颜色strokeWidth:线条粗细dot:数据点样式(设为false可隐藏)activeDot:悬停时的数据点样式connectNulls:设为 true 可连接间隔
面积图
<AreaChart data={data}>
<defs>
<linearGradient id="colorValue" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#8884d8" stopOpacity={0.8}/>
<stop offset="95%" stopColor="#8884d8" stopOpacity={0}/>
</linearGradient>
</defs>
<XAxis dataKey="name" />
<YAxis />
<CartesianGrid strokeDasharray="3 3" />
<Tooltip />
<Area type="monotone" dataKey="value" stroke="#8884d8" fillOpacity={1} fill="url(#colorValue)" />
</AreaChart>
堆叠面积图:
<Area type="monotone" dataKey="sales" stackId="1" stroke="#8884d8" fill="#8884d8" />
<Area type="monotone" dataKey="profit" stackId="1" stroke="#82ca9d" fill="#82ca9d" />
条形图
<BarChart data={data}>
<XAxis dataKey="name" />
<YAxis />
<CartesianGrid strokeDasharray="3 3" />
<Tooltip />
<Legend />
<Bar dataKey="sales" fill="#8884d8" radius={[4, 4, 0, 0]} />
<Bar dataKey="profit" fill="#82ca9d" radius={[4, 4, 0, 0]} />
</BarChart>
关键属性:
fill:条形颜色radius:圆角 [左上、右上、右下、左下],或为所有角设置单个数值barSize:固定条形宽度stackId:将条形分组堆叠shape:自定义条形形状(函数或元素)
堆叠条形图:
<Bar dataKey="sales" stackId="a" fill="#8884d8" />
<Bar dataKey="profit" stackId="a" fill="#82ca9d" />
圆角堆叠条形图(使用 BarStack 为整个堆叠设置圆角):
import { BarStack } from 'recharts';
<BarChart data={data}>
<BarStack stackId="a" radius={[4, 4, 0, 0]}>
<Bar dataKey="sales" fill="#8884d8" />
<Bar dataKey="profit" fill="#82ca9d" />
</BarStack>
</BarChart>
饼图
const COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042'];
<PieChart>
<Pie
data={data}
dataKey="value"
nameKey="name"
cx="50%"
cy="50%"
innerRadius={60}
outerRadius={80}
paddingAngle={5}
shape={(props) => <Sector {...props} fill={COLORS[props.index % COLORS.length]} />}
/>
<Tooltip />
<Legend />
</PieChart>
关键属性:
innerRadius:大于 0 时创建环形图outerRadius:饼图尺寸paddingAngle:扇区之间的间隙startAngle/endAngle:部分饼图(默认:0 到 360)label:在扇区上显示数值shape:自定义每个扇区的渲染方式(替代已弃用的Cell组件)
散点图
<ScatterChart>
<XAxis type="number" dataKey="x" name="X Axis" />
<YAxis type="number" dataKey="y" name="Y Axis" />
<CartesianGrid />
<Tooltip cursor={{ strokeDasharray: '3 3' }} />
<Scatter name="Series A" data={data} fill="#8884d8" />
</ScatterChart>
组合图
混合多种图表类型:
<ComposedChart data={data}>
<XAxis dataKey="name" />
<YAxis />
<CartesianGrid stroke="#f5f5f5" />
<Tooltip />
<Legend />
<Area type="monotone" dataKey="total" fill="#8884d8" stroke="#8884d8" />
<Bar dataKey="sales" barSize={20} fill="#413ea0" />
<Line type="monotone" dataKey="profit" stroke="#ff7300" />
</ComposedChart>
响应式尺寸
选项 1:responsive 属性(Recharts 3.3+,推荐)
在图表本身设置 responsive。使用标准 CSS 尺寸规则:
<LineChart data={data} width="100%" height={300} responsive>
{/* chart components */}
</LineChart>
适用于 flexbox 和 CSS grid 布局。还支持 CSS style 属性:
<LineChart data={data} responsive style={{ maxWidth: 800, width: '100%', aspectRatio: '16/9' }}>
{/* chart components */}
</LineChart>
选项 2:ResponsiveContainer(较早版本)
对于 Recharts < 3.3,请使用 ResponsiveContainer 封装图表:
<ResponsiveContainer width="100%" height={300}>
<LineChart data={data}>
{/* chart components */}
</LineChart>
</ResponsiveContainer>
重要:ResponsiveContainer 必须有一个尺寸已定义的父元素。高度必须是数值,不能是百分比。
固定尺寸
直接以像素或百分比设置 width 和 height:
<LineChart data={data} width={600} height={300}>
{/* chart components */}
</LineChart>
轴配置
XAxis / YAxis 属性
<XAxis
dataKey="name" // property to display
type="category" // "category" or "number"
domain={[0, 'dataMax']} // axis range
tick={{ fill: '#666' }} // tick styling
tickFormatter={(value) => `$${value}`} // format labels
angle={-45} // rotate labels
textAnchor="end" // text alignment
height={60} // extra space for labels
/>
轴类型
- 类别轴(X 轴默认):将值视为离散标签
- 数值轴(Y 轴默认):将值视为连续刻度
自定义范围
控制轴的范围:
// Fixed range
<YAxis domain={[0, 100]} />
// Auto with padding
<YAxis domain={[0, 'auto']} />
// Data-based with overflow allowed
<YAxis domain={[0, 'dataMax + 100']} allowDataOverflow />
// Logarithmic scale
<YAxis type="number" scale="log" domain={['auto', 'auto']} />
自定义
自定义提示框
const CustomTooltip = ({ active, payload, label }) => {
if (active && payload && payload.length) {
return (
<div className="custom-tooltip">
<p className="label">{`${label}`}</p>
<p className="intro">{`Sales: ${payload[0].value}`}</p>
<p className="desc">Additional info...</p>
</div>
);
}
return null;
};
<Tooltip content={<CustomTooltip />} />
自定义图例
const CustomLegend = ({ payload }) => (
<ul>
{payload.map((entry, index) => (
<li key={`item-${index}`} style={{ color: entry.color }}>
{entry.value}
</li>
))}
</ul>
);
<Legend content={<CustomLegend />} />
自定义形状
自定义条形形状:
const CustomBar = (props) => {
const { x, y, width, height, fill } = props;
return <path d={`M${x},${y} ...`} fill={fill} />;
};
<Bar shape={<CustomBar />} dataKey="sales" />
// OR
<Bar shape={(props) => <CustomBar {...props} />} dataKey="sales" />
自定义标签
<Line
dataKey="sales"
label={{ position: 'top', fill: '#666', fontSize: 12 }}
/>
// Custom label component
<Line
dataKey="sales"
label={<CustomLabel />}
/>
样式
图表样式:
<LineChart style={{ backgroundColor: '#f5f5f5' }}>
轴样式:
<XAxis
axisLine={{ stroke: '#666' }}
tickLine={{ stroke: '#666' }}
tick={{ fill: '#666', fontSize: 12 }}
/>
网格样式:
<CartesianGrid strokeDasharray="3 3" stroke="#e0e0e0" />
交互
活动元素与交互控制
Tooltip 组件控制活动元素的高亮显示。请勿使用 activeIndex prop(已在 v3 中移除)。
Tooltip 交互 props:
defaultIndex:设置渲染时初始高亮的项active:如果为 true,交互结束后 Tooltip 仍保持活动状态trigger:"hover"(默认)或"click",用于基于点击的交互content:自定义内容,或使用() => null隐藏 Tooltip 文本,同时保留高亮cursor:绘图区中的可视光标,设为false可将其隐藏
{/* Click-based interaction with hidden tooltip text */}
<Tooltip trigger="click" content={() => null} cursor={false} />
{/* Default highlighted item on render */}
<Tooltip defaultIndex={2} />
点击事件
<LineChart onClick={(e) => console.log(e)}>
<Bar
dataKey="sales"
onClick={(data, index) => console.log('Bar clicked:', data)}
/>
</LineChart>
同步图表
使用 syncId 关联多个图表:
<LineChart data={data1} syncId="anyId">
{/* components */}
</LineChart>
<LineChart data={data2} syncId="anyId">
{/* components - tooltips synchronize */}
</LineChart>
使用 Brush 缩放
<LineChart data={data}>
{/* other components */}
<Brush dataKey="name" height={30} stroke="#8884d8" />
</LineChart>
性能优化
1. 保持引用稳定
对 props 使用 useMemo 和 useCallback:
// BAD - new function on every render
<Line dataKey={(entry) => entry.sales * 2} />
// GOOD - stable reference
const dataKey = useCallback((entry) => entry.sales * 2, []);
<Line dataKey={dataKey} />
2. 对组件进行记忆化
const MemoizedChart = React.memo(({ data }) => (
<LineChart data={data}>
{/* components */}
</LineChart>
));
3. 隔离变化的组件
分离频繁更新的组件:
const Chart = () => {
const [hoveredData, setHoveredData] = useState(null);
return (
<LineChart>
{/* Static components */}
<Line dataKey="sales" />
{/* Dynamic overlay */}
<ReferenceLine x={hoveredData?.x} stroke="red" />
</LineChart>
);
};
4. 对事件进行防抖
import { useDebouncedCallback } from 'use-debounce';
const handleMouseMove = useDebouncedCallback((e) => {
setPosition(e.activeLabel);
}, 10);
<LineChart onMouseMove={handleMouseMove}>
5. 减少数据点
对于大型数据集,可考虑聚合数据:
// Bin data before rendering
const binnedData = useMemo(() => {
return d3.bin().value(d => d.x)(rawData);
}, [rawData]);
无障碍
Recharts 内置无障碍支持:
<LineChart accessibilityLayer={true}>
<Line dataKey="sales" name="Monthly Sales" />
</LineChart>
默认启用无障碍功能。图表支持键盘导航,并兼容屏幕阅读器。
ARIA props:
<LineChart role="img" aria-label="Sales chart showing monthly revenue">
常见模式
多个数据系列
<LineChart data={data}>
<XAxis dataKey="month" />
<YAxis />
<Tooltip />
<Legend />
<Line type="monotone" dataKey="productA" name="Product A" stroke="#8884d8" />
<Line type="monotone" dataKey="productB" name="Product B" stroke="#82ca9d" />
<Line type="monotone" dataKey="productC" name="Product C" stroke="#ffc658" />
</LineChart>
水平条形图
<BarChart layout="vertical" data={data}>
<XAxis type="number" />
<YAxis type="category" dataKey="name" />
<Bar dataKey="value" />
</BarChart>
环形图
const COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042'];
<PieChart>
<Pie
data={data}
innerRadius={60}
outerRadius={80}
paddingAngle={5}
dataKey="value"
shape={(props) => <Sector {...props} fill={COLORS[props.index % COLORS.length]} />}
/>
</PieChart>
注意:
Cell组件已弃用,并将在 Recharts 4.0 中移除。请改用Bar、Pie、Scatter等组件的shapeprop。
参考线/区域
<LineChart data={data}>
{/* ... */}
<ReferenceLine y={5000} label="Target" stroke="red" strokeDasharray="3 3" />
<ReferenceArea x1="Jan" x2="Mar" fill="#8884d8" fillOpacity={0.1} />
</LineChart>
误差线
<ScatterChart>
<Scatter data={data}>
<ErrorBar dataKey="errorX" width={4} strokeWidth={2} />
<ErrorBar dataKey="errorY" width={4} strokeWidth={2} direction="y" />
</Scatter>
</ScatterChart>
集成模式
与状态管理集成
const SalesChart = () => {
const [timeRange, setTimeRange] = useState('month');
const data = useSelector(state => selectSalesData(state, timeRange));
return (
<ResponsiveContainer>
<LineChart data={data}>
{/* components */}
</LineChart>
</ResponsiveContainer>
);
};
与实时数据集成
const RealtimeChart = () => {
const [data, setData] = useState([]);
useEffect(() => {
const interval = setInterval(() => {
setData(prev => [...prev.slice(-20), newDataPoint]);
}, 1000);
return () => clearInterval(interval);
}, []);
return (
<LineChart data={data}>
<XAxis dataKey="time" />
<YAxis domain={['auto', 'auto']} />
<Line type="monotone" dataKey="value" isAnimationActive={false} />
</LineChart>
);
};
Z 轴索引与图层(v3.4+)
组件按默认顺序渲染(网格 < 坐标轴 < 图表元素 < Tooltip/图例)。使用 zIndex prop 覆盖:
<Line dataKey="sales" zIndex={10} /> // Render on top
对于不直接支持 zIndex 的组件,可将其包裹在 ZIndexLayer 中:
import { ZIndexLayer } from 'recharts';
<ZIndexLayer zIndex={5}>
<CustomAnnotation />
</ZIndexLayer>
坐标系
Recharts 有三种坐标系:
- 域坐标 - 数据值(例如,
x="March"、y=5000)。由ReferenceLine、ReferenceDot、ReferenceArea使用。会自动转换为像素。 - 像素坐标 - 相对于图表 viewBox 的位置。用于自定义 SVG 形状。可通过
usePlotArea()、useOffset()、useChartWidth()hooks 访问。 - 鼠标事件坐标 - 浏览器视口坐标。使用
getRelativeCoordinate(event, element)转换。
坐标系之间的转换:
- 数据转像素:
useXAxisScale()、useYAxisScale() - 像素转数据:
useXAxisInverseScale()、useYAxisInverseScale()
故障排除
图表未渲染
- 确保
ResponsiveContainer的父元素具有明确的尺寸 - 检查 height 是否为数字(在 ResponsiveContainer 中不能使用百分比)
- 确认 data 是对象数组
Tooltip 未显示
- 确保已包含 Tooltip 组件
- 检查数据对象中是否存在 dataKey 值
坐标轴标签重叠
- 旋转标签:
<XAxis angle={-45} textAnchor="end" height={80} /> - 使用 interval:
<XAxis interval={0} />(0 = 显示全部,'preserveStartEnd' = 自动)
动画问题
- 禁用动画:
<Line isAnimationActive={false} /> - 缩短时长:
<Line animationDuration={500} />