TuBrief
구독 채널
비디오
커뮤니티

Rechartsで重くなったダッシュボードのバンドルをTanStack Chartsで軽くする方法

TuBrief 편집팀
2026년 8월 12일
0
Computing/Software

원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.

日本語한국어EnglishEspañol中文العربيةहिन्दीDeutschFrançaisPortuguêsРусскийBahasa Indonesia

관련 영상

TanStackがまたやってくれた... チャート機能を刷新8:14

TanStackがまたやってくれた... チャート機能を刷新

Better Stack

커뮤니티의 다른 글

사내 시스템에 llm api 붙일 때 마주하는 현실적인 한계와 대응법

2026년 9월 13일

레거시 백엔드에 GPT-6 Astra 붙일 때 예산 승인과 보안 통과를 먼저 끝내는 법이 있습니다

2026년 9월 13일

에이전트끼리 대화하다 6천만 원 청구서가 나오는 이유

2026년 9월 13일

사내 RAG 벡터 검색에 Okta 권한 필터를 직접 거는 방법

2026년 9월 13일

브라우저 에이전트에게 내 구글 계정을 통째로 넘기면 안 되는 이유

2026년 9월 12일

Apple Won the AI Race

2026년 9월 12일

댓글 (0)

Log in to leave a comment

아직 작성된 글이 없습니다

© 2026 . All rights reserved.

TuBrief
구독 채널
비디오
커뮤니티
로그인

Rechartsで重くなったダッシュボードのバンドルをTanStack Chartsで軽くする方法

ダッシュボードのページを開いたのに、チャートの読み込みに時間がかかって砂時計が回っているなら、十中八九Rechartsが原因だ。チャートをいくつか置いただけでバンドルサイズが数百キロバイトも膨らむのを見ると、思わずため息が出る。RechartsはReact DOMの調整サイクルに深く結びつきすぎている。UI構造とデータ処理が絡み合っていて、気軽な気持ちで使うのが難しい。

そんな時にTanStack Chartsが良い代替案になる。可視化ロジックをグラフィック文法ベースのコアに分離しているからだ。Rechartsが通常150KiB以上を食うのに対し、TanStack Chartsは約40KiB前後だ。バンドルサイズが70%近くも削減される。

問題はプロダクションコードの移行だ。うまく動いている画面を書き換えるのはいつだって気が引ける。チームメンバーを説得し、トラブルなく移行するには明確な手順が必要だ。

Rechartsのコードを安全に剥がす

一度に全部変えようとすると、どこでバグったのか探すのも一苦労だ。コンポーネントを1つずつ取り上げ、ぴったり4つのステップに分けて進めよう。

  1. データ前処理の分離: RechartsコンポーネントのJSX内に混ざっていたデータ加工ロジックを、純粋関数として外に切り出す。
  2. マークのマッピング: 軸の設定や、線、点などの視覚要素を defineChart 宣言オブジェクトの marks 配列に移動する。
  3. ユーティリティの置き換え: ResponsiveContainer と Tooltip を、TanStackの自動スケーラーと @tanstack/charts/tooltip モジュールに置き換える。
  4. メモ化: チャート定義オブジェクトを useMemo で包み、最上位の Chart コンポーネントに渡す。

この手順さえ守れば、最初のチャートコンポーネントを置き換えるのにかかる時間を半分に短縮できる。

`typescript
import React, { useMemo } from 'react';
import { defineChart, lineY, dot } from '@tanstack/charts';
import { scaleBand } from '@tanstack/charts/scales/band';
import { scaleLinear } from '@tanstack/charts/scales/linear';
import { tooltip } from '@tanstack/charts/tooltip';
import { Chart } from '@tanstack/charts/react';

interface DataRow {
date: string;
value: number;
}

export function MigratedRevenueChart({ data }: { data: DataRow[] }) {
const definition = useMemo(() => {
return defineChart({
marks: [
lineY(data, {
x: 'date',
y: 'value',
stroke: 'var(--ts-chart-1, #2563eb)',
strokeWidth: 2,
}),
dot(data, {
x: 'date',
y: 'value',
fill: 'var(--ts-chart-1, #2563eb)',
r: 4,
}),
],
x: {
scale: () => scaleBand().padding(0.2),
},
y: {
scale: scaleLinear,
nice: true,
grid: true,
},
tooltip: {
use: tooltip,
className: 'custom-tooltip',
},
});
}, [data]);

return (
<div style={{ width: '100%', height: 300 }}>


);
}

`

ダークモード対応時にJavaScriptの再レンダリングをなくす

ダークモードを切り替えるたびにチャートコンポーネント全体が再描画されるのはスマートではない。TanStack Chartsはハードコードされた色の値の代わりに、CSSカスタムプロパティと currentColor をそのままサポートしている。

チャートの色をJavaScriptの状態として管理するのではなく、CSS変数に落とし込もう。チャートのデフォルトパレットは --ts-chart-1 から --ts-chart-6 までを参照するようにすればよい。

  1. CSSのルートと [data-theme='dark'] に、チャート用の変数をあらかじめ定義しておく。
  2. defineChart オプションの stroke や fill に var(--ts-chart-1) のような文字列を入れる。
  3. ツールチップのスタイルもCSSクラスで管理し、背景色を変数で処理する。

このように組んでおけば、デザイナーからチャートの色を変えてほしいと言われてもTSXファイルを触る必要がない。CSSを修正するだけで終わる。

`css
:root {
--bg-chart-card: #ffffff;
--text-chart-main: #172033;
--border-chart-grid: #e2e8f0;
--ts-chart-1: #2563eb;
--ts-chart-2: #f97316;
}

[data-theme='dark'] {
--bg-chart-card: #0f172a;
--text-chart-main: #f8fafc;
--border-chart-grid: #334155;
--ts-chart-1: #60a5fa;
--ts-chart-2: #fb923c;
}

.custom-tooltip {
background-color: var(--bg-chart-card);
color: var(--text-chart-main);
border: 1px solid var(--border-chart-grid);
padding: 8px 12px;
border-radius: 6px;
}

`

10万件のデータをブチ込んでもクラッシュさせない方法

10万個のポイントをSVGでレンダリングすると、DOMノードが10万個生成される。ブラウザのスレッドが耐えられるわけがない。カクつくのが目に見えてわかる。

解決策は2つを組み合わせることだ。Canvasレンダラーに切り替えてDOM生成のコストをなくし、画面のピクセル幅に対して無駄に密集しているデータはLTTB(Largest Triangle Three Buckets)アルゴリズムで圧縮する。LTTBはデータの尖った特徴(最大値、最小値)を維持しながら、ポイントの数を減らしてくれる。

`typescript
export function lttbDownsample(
data: T[],
xAccessor: (d: T) => number,
yAccessor: (d: T) => number,
threshold: number
): T[] {
const dataLength = data.length;
if (threshold >= dataLength || threshold === 0) return data;

const sampled: T[] = [];
let sampledIndex = 0;
const bucketSize = (dataLength - 2) / (threshold - 2);

sampled[sampledIndex++] = data[0];

for (let i = 0; i < threshold - 2; i++) {
let avgX = 0;
let avgY = 0;
const avgRangeStart = Math.floor((i + 1) * bucketSize) + 1;
const avgRangeEnd = Math.floor((i + 2) * bucketSize) + 1;
const currentAvgRangeEnd = avgRangeEnd < dataLength ? avgRangeEnd : dataLength;

for (let j = avgRangeStart; j < currentAvgRangeEnd; j++) {
  avgX += xAccessor(data[j]);
  avgY += yAccessor(data[j]);
}
avgX /= (currentAvgRangeEnd - avgRangeStart);
avgY /= (currentAvgRangeEnd - avgRangeStart);

const rangeOffs = Math.floor((i + 0) * bucketSize) + 1;
const rangeTo = Math.floor((i + 1) * bucketSize) + 1;
const pointAX = xAccessor(sampled[sampledIndex - 1]);
const pointAY = yAccessor(sampled[sampledIndex - 1]);

let maxArea = -1;
let maxAreaPointIndex = rangeOffs;

for (let j = rangeOffs; j < rangeTo; j++) {
  const area = Math.abs(
    (pointAX - avgX) * (yAccessor(data[j]) - pointAY) -
    (pointAX - xAccessor(data[j])) * (avgY - pointAY)
  ) * 0.5;

  if (area > maxArea) {
    maxArea = area;
    maxAreaPointIndex = j;
  }
}
sampled[sampledIndex++] = data[maxAreaPointIndex];

}

sampled[sampledIndex++] = data[dataLength - 1];
return sampled;
}

`

大容量の時系列データを扱うときは、LTTBで1000件程度まで減らして渡そう。そして spatialIndex: true オプションを有効にして、マウスポインターの検出複雑度を下げる。最後に @tanstack/charts/react/canvas パッケージのCanvasレンダラーを組み込めば、60fpsを叩き出せる。

CursorやCopilotにチャートコードを任せるコツ

RechartsのようにJSXタグが深くネストしている形式は、AIアシスタントがハルシネーションを起こしやすい。変なプロパティを作り出したり、開きタグを閉じなかったりする。

TanStack Chartsのようにオブジェクト宣言式で記述されるライブラリは、型スキーマさえしっかりと与えておけばAIが綺麗なコードをきれいに吐き出してくれる。プロジェクトに次のようなスキーマ型を1つ定義しておき、AIのプロンプトやルールファイル(.cursorrules)に組み込んでおこう。

`typescript
export type ScaleType = 'linear' | 'band' | 'utc' | 'point';
export type MarkType = 'lineY' | 'barY' | 'dot' | 'areaY';

export interface AIScaleConfig {
type: ScaleType;
nice?: boolean;
grid?: boolean;
padding?: number;
}

export interface AIMarkConfig {
type: MarkType;
xKey: string;
yKey: string;
color?: string;
strokeWidth?: number;
}

export interface AIChartGenerationSchema {
data: Record<string, unknown>[];
scales: {
x: AIScaleConfig;
y: AIScaleConfig;
};
marks: AIMarkConfig[];
tooltip?: {
enabled: boolean;
className?: string;
};
}

`

@tanstack/charts/scales/linear のように正確なサブパスからインポートするというルールや、 useMemo を使用するルールをプロンプトに書いておけば、AIが生成したコードを修正なしでそのまま使うことができる。