---
id: react-charts-library-comparison
title: React Charts — Recharts / Visx / D3 / Tremor
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [react, charts, dataviz, vibe-coding]
tech_stack: { language: "TS / React", applicable_to: ["Frontend"] }
applied_in: []
aliases: [Recharts, Visx, D3, Tremor, Nivo, Chart.js, dataviz]
---

# React Charts

> **Recharts = 빠른 시작, 한정**. **Visx (Airbnb) = D3 위 React 컴포넌트, 유연**. **D3 직접 = 풀 컨트롤**. **Tremor / shadcn charts = dashboard UI 일관성**.

## 📖 핵심 개념
- High-level: 차트 종류 직접 (Bar, Line). 빠른 시작.
- Low-level: scale / axis / shape 조립. 유연.
- Headless: 행동만, 스타일 너의 것.

## 💻 코드 패턴

### Recharts (간단)
```tsx
import { LineChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer } from 'recharts';

<ResponsiveContainer width="100%" height={300}>
  <LineChart data={data}>
    <XAxis dataKey="date" />
    <YAxis />
    <Tooltip />
    <Line type="monotone" dataKey="value" stroke="#3b82f6" />
  </LineChart>
</ResponsiveContainer>
```

→ Pros: 5분 setup. Cons: 복잡 customization 어려움, 큰 데이터 느림.

### Tremor (대시보드 UI)
```tsx
import { Card, AreaChart, Title, Metric, Flex, BadgeDelta } from '@tremor/react';

<Card>
  <Flex>
    <Title>Sales</Title>
    <BadgeDelta deltaType="moderateIncrease">+12%</BadgeDelta>
  </Flex>
  <Metric>$12,345</Metric>
  <AreaChart data={data} index="date" categories={['sales']} colors={['blue']} />
</Card>
```

→ Tailwind based. Dashboard 만들기 빠름.

### Visx (Airbnb, low-level + React)
```tsx
import { LinePath } from '@visx/shape';
import { scaleLinear } from '@visx/scale';
import { AxisBottom, AxisLeft } from '@visx/axis';
import { GridRows, GridColumns } from '@visx/grid';

const xScale = scaleLinear({ domain: [0, 100], range: [0, width] });
const yScale = scaleLinear({ domain: [0, 100], range: [height, 0] });

<svg width={width + 60} height={height + 40}>
  <g transform="translate(40, 10)">
    <GridRows scale={yScale} width={width} />
    <GridColumns scale={xScale} height={height} />
    <LinePath
      data={data}
      x={d => xScale(d.x)}
      y={d => yScale(d.y)}
      stroke="#3b82f6"
      strokeWidth={2}
    />
    <AxisLeft scale={yScale} />
    <AxisBottom scale={xScale} top={height} />
  </g>
</svg>
```

→ Pros: D3 의 power + React 의 declarative. Cons: 학습 곡선.

### D3 직접 (max 컨트롤)
```tsx
import * as d3 from 'd3';
import { useEffect, useRef } from 'react';

function Chart({ data }: { data: { x: number; y: number }[] }) {
  const ref = useRef<SVGSVGElement>(null);

  useEffect(() => {
    const svg = d3.select(ref.current);
    const x = d3.scaleLinear().domain(d3.extent(data, d => d.x) as [number, number]).range([0, 400]);
    const y = d3.scaleLinear().domain([0, d3.max(data, d => d.y)!]).range([200, 0]);

    const line = d3.line<typeof data[0]>().x(d => x(d.x)).y(d => y(d.y));

    svg.append('path')
       .datum(data)
       .attr('d', line)
       .attr('fill', 'none')
       .attr('stroke', '#3b82f6');
  }, [data]);

  return <svg ref={ref} width={400} height={200} />;
}
```

→ React 와 D3 dual responsibility — declarative 깨질 수 있음.

### shadcn charts (Recharts wrapper, Tailwind theme)
```tsx
import { ChartContainer, ChartTooltip, ChartTooltipContent, ChartConfig } from '@/components/ui/chart';
import { Bar, BarChart, XAxis } from 'recharts';

const config = {
  sales: { label: 'Sales', color: 'hsl(var(--chart-1))' },
} satisfies ChartConfig;

<ChartContainer config={config}>
  <BarChart data={data}>
    <XAxis dataKey="month" />
    <ChartTooltip content={<ChartTooltipContent />} />
    <Bar dataKey="sales" fill="var(--color-sales)" radius={4} />
  </BarChart>
</ChartContainer>
```

→ Recharts power + shadcn theming + a11y.

### 큰 데이터 — canvas
```tsx
// React-vis-style 또는 직접 canvas
import { Canvas } from '@react-three/fiber'; // 3D 차트
// 또는 visx/visx-glyph + canvas renderer
```

10K+ 점 = SVG 느림. Canvas 또는 WebGL.

### Animation
```tsx
// Recharts: animation 자동 (animationDuration)
<Line dataKey="v" isAnimationActive={true} animationDuration={500} />

// Visx + framer-motion
<motion.path d={pathD} initial={{ pathLength: 0 }} animate={{ pathLength: 1 }} />
```

## 🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| 빠른 dashboard | Tremor |
| 단순 차트 | Recharts |
| Custom + Tailwind 일관성 | shadcn charts |
| 복잡 / 유연 | Visx |
| 풀 컨트롤 + 큰 데이터 | D3 + canvas |
| 3D / WebGL | three.js / r3f |
| Native mobile | Victory Native / react-native-skia |

## ❌ 안티패턴
- **Recharts 로 10K 점**: 느림. Canvas.
- **D3 + React 같이 DOM 조작**: race. D3 가 SVG 만들고 React 가 render layer.
- **차트 안에 큰 ResponsiveContainer 매번 resize**: ResizeObserver throttle.
- **Tooltip 매 hover 새 객체**: re-render. memoize.
- **색 hard-code**: 다크모드 X. theme 사용.
- **Axis 너무 많은 tick**: 가독성 낮음. format / count 제한.
- **A11y 무시 — SVG only**: aria-label / 표 alternative.

## 🤖 LLM 활용 힌트
- 시작 = Recharts / Tremor.
- 큰 / 유연 = Visx.
- shadcn charts 가 Tailwind 사용자에게 sweet spot.

## 🔗 관련 문서
- [[Frontend_Design_Tokens]]
- [[React_Animation_Performance]]
- [[Frontend_A11y_Testing]]
