mcpField
R
recharts

recharts

github.com/andy-spike设计与 UI11.1k 次安装32 周前更新
代码仓库

关于 recharts

Recharts 是基于 D3 的 React 图表库,面向构建声明式、可组合数据可视化的开发者。它提供多种图表组件、响应式尺寸设置,以及交互和无障碍支持。

主要功能

  1. 01可组合的 React 图表组件
  2. 02折线、柱形、面积、饼图等类型
  3. 03响应式与固定尺寸
  4. 04自定义提示框、标签和形状
  5. 05图表交互与同步
  6. 06支持键盘和屏幕阅读器

适用场景

  1. 01在 React 界面中构建数据图表
  2. 02在单个可视化中组合多种图表
  3. 03创建响应式仪表板
  4. 04添加交互式无障碍图表

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/andy-spike/skills --skill recharts

安装后在 Claude Code 中输入/recharts确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
api_reference.md
best_practices.md
examples.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 等组件的 shape prop。

参考线/区域
<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 有三种坐标系:

  1. 域坐标 - 数据值(例如,x="March"、y=5000)。由 ReferenceLine、ReferenceDot、ReferenceArea 使用。会自动转换为像素。
  2. 像素坐标 - 相对于图表 viewBox 的位置。用于自定义 SVG 形状。可通过 usePlotArea()、useOffset()、useChartWidth() hooks 访问。
  3. 鼠标事件坐标 - 浏览器视口坐标。使用 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} />

资源

参考资料
外部资源

评论

支持 Markdown