Data Loading
There are two ways to get data into the chart: a static data array, or a dataLoader for streaming and pagination.
Static data
Section titled “Static data”Pass an array of KLineData. Replacing the array re-applies the data; mutating it in place does not.
const [data, setData] = useState<KLineData[]>(initialBars);
<KLineChart data={data} />;
// Later: a new reference triggers a reloadsetData((prev) => [...prev, newBar]);Under the hood, a static data array is wrapped in a minimal loader that reports { forward: false, backward: false } — i.e. there is no older history to load on scroll-left.
DataLoader (recommended for real apps)
Section titled “DataLoader (recommended for real apps)”For realtime data and history pagination, implement a DataLoader. KlineCharts owns the data flow and calls your methods at the right times.
interface DataLoader { getBars: (params: DataLoaderGetBarsParams) => void | Promise<void>; subscribeBar?: (params: DataLoaderSubscribeBarParams) => void; unsubscribeBar?: (params: DataLoaderUnsubscribeBarParams) => void;}getBars— called on init and when the user scrolls left past the available bars (type: "forward"). Callcallback(data, more)with the bars and whether more history is available in each direction.subscribeBar— callcallback(bar)to push realtime updates (a new bar, or an updated current bar).unsubscribeBar— clean up (close sockets, clear timers).
Example: synthetic realtime feed
Section titled “Example: synthetic realtime feed”import { useMemo } from "react";import type { DataLoader } from "react-klinecharts";
function useRealtimeLoader(): DataLoader { return useMemo(() => { let intervalId: ReturnType<typeof setInterval> | null = null; let lastBar: KLineData | null = null;
return { getBars: ({ callback }) => { const data = generateInitialBars(); lastBar = data[data.length - 1]; callback(data, { forward: false, backward: false }); }, subscribeBar: ({ callback }) => { intervalId = setInterval(() => { if (!lastBar) return; lastBar = nextTick(lastBar); callback(lastBar); }, 500); }, unsubscribeBar: () => { if (intervalId) clearInterval(intervalId); }, }; }, []);}
<KLineChart dataLoader={useRealtimeLoader()} symbol={{ ticker: "DEMO" }} period={{ type: "minute", span: 1 }} />Example: exchange REST + WebSocket (Binance)
Section titled “Example: exchange REST + WebSocket (Binance)”const loader: DataLoader = { getBars: async ({ type, callback }) => { if (type === "init") { const history = await fetchKlines(symbol, period); callback(history, { forward: true, backward: false }); } else if (type === "forward") { const older = await fetchOlderBars(symbol, period); callback(older, { forward: older.length > 0, backward: false }); } }, subscribeBar: ({ callback }) => { const ws = new WebSocket(`wss://stream.exchange.com/${symbol}@kline`); ws.onmessage = (e) => callback(parseTick(JSON.parse(e.data))); return () => ws.close(); },};Symbol & period
Section titled “Symbol & period”symbol and period are serialized (not compared by reference) before becoming effect dependencies, so passing an inline object won’t trigger a redundant reload:
// Safe — these are stable across renders even though the object is inline<KLineChart symbol={{ ticker: "BTC/USDT", pricePrecision: 2 }} period={{ type: "minute", span: 15 }}/>Changing the symbol or period triggers chart.setSymbol() / chart.setPeriod(), which in turn asks your dataLoader for fresh bars.