Como reduzir o tamanho de pacotes de painéis pesados do Recharts usando o TanStack Charts
TuBrief 편집팀
2026년 8월 12일
0
Computing/Software원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
커뮤니티의 다른 글
댓글 (0)
Log in to leave a comment
아직 작성된 글이 없습니다
원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.
Log in to leave a comment
아직 작성된 글이 없습니다
Se você entra em uma página de painel e a ampulheta fica girando só para carregar os gráficos, é quase certeza que o problema é o Recharts. Fica difícil não suspirar ao ver o tamanho do pacote inchar em centenas de quilobytes só por adicionar alguns gráficos. O Recharts fica grudado demais no ciclo de reconciliação do React. A estrutura de UI e o processamento de dados ficam emaranhados, tornando o uso leve algo difícil.
Nesses momentos, o TanStack Charts se torna uma alternativa sólida. Ele separa a lógica de visualização em um núcleo baseado em gramática gráfica. Enquanto o Recharts costuma consumir mais de 150 KiB, o TanStack Charts fica em torno de 40 KiB. O tamanho do pacote diminui em quase 70%.
O desafio é a migração do código em produção. Substituir telas que já funcionam bem sempre gera um frio na barriga. Para convencer a equipe e realizar a transição sem quebras, é preciso seguir uma ordem clara.
Tentar mudar tudo de uma vez dificulta muito a localização de erros. É preciso isolar um componente e fazer a transição dividindo-a em exatamente 4 etapas:
marks do objeto de declaração defineChart.ResponsiveContainer e o Tooltip pelo dimensionador automático do TanStack e pelo módulo @tanstack/charts/tooltip.useMemo e passe-o para o componente raiz Chart.Apenas seguindo essa ordem, o tempo necessário para substituir o primeiro componente de gráfico é reduzido pela metade.
`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 }}>
);
}
`
Fazer com que o componente de gráfico inteiro seja redesenhado toda vez que o modo escuro for alternado é deselegante. O TanStack Charts suporta nativamente propriedades customizadas de CSS e currentColor em vez de valores de cores hardcoded.
Em vez de gerenciar as cores dos gráficos no estado do JavaScript, passe-as por variáveis CSS. Basta fazer com que a paleta padrão do gráfico faça referência de --ts-chart-1 até --ts-chart-6.
[data-theme='dark'].var(--ts-chart-1) em stroke ou fill nas opções do defineChart.Ao estruturar dessa forma, quando o designer pedir para alterar a cor do gráfico, não será necessário mexer nos arquivos TSX. Basta ajustar o 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;
}
`
Renderizar 100 mil pontos em SVG gera 100 mil nós no DOM. A thread do navegador simplesmente não aguenta. A lentidão fica perceptível.
A solução consiste em combinar duas abordagens: alternar para o renderizador de Canvas para eliminar o custo de criação do DOM e comprimir dados desnecessariamente densos em relação à largura em pixels da tela usando o algoritmo LTTB (Largest Triangle Three Buckets). O LTTB reduz a quantidade de pontos preservando as características marcantes dos dados (valores máximos e mínimos).
`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;
}
`
Ao lidar com séries temporais de grande volume, reduza os dados para cerca de 1000 itens usando o LTTB antes de repassá-los. Em seguida, ative a opção spatialIndex: true para diminuir a complexidade de detecção do ponteiro do mouse. Por fim, adicione o renderizador de Canvas do pacote @tanstack/charts/react/canvas para garantir uma taxa fluida de 60 fps.
Bibliotecas com tags JSX profundamente aninhadas, como o Recharts, costumam fazer com que assistentes de IA gerem alucinações facilmente. Eles inventam propriedades estranhas ou deixam tags abertas.
Bibliotecas baseadas em declaração de objetos, como o TanStack Charts, geram códigos limpos pela IA desde que se forneça o esquema de tipos adequado. Defina um tipo de esquema como o abaixo em seu projeto e inclua-o nas instruções de prompt da IA ou no arquivo de regras (.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;
};
}
`
Se você adicionar regras ao prompt — como instruir a IA a importar a partir de subcaminhos precisos (ex: @tanstack/charts/scales/linear) e a utilizar o useMemo —, poderá utilizar o código gerado pela IA imediatamente, sem necessidade de correções.