종목변경 시 캔들차트 사라지는 현상 수정
This commit is contained in:
@@ -53,6 +53,8 @@ interface Options {
|
||||
|
||||
interface Return {
|
||||
bars: OHLCVBar[];
|
||||
/** bars 가 어느 종목 기준인지 (로딩 중·전환 직후 null) */
|
||||
barsMarket: string | null;
|
||||
latestBar: OHLCVBar | null;
|
||||
wsStatus: WsStatus;
|
||||
isLoading: boolean;
|
||||
@@ -105,6 +107,7 @@ export function useStompChartData(
|
||||
): Return {
|
||||
const candleType = timeframeToCandleType(timeframe);
|
||||
const [bars, setBars] = useState<OHLCVBar[]>([]);
|
||||
const [barsMarket, setBarsMarket] = useState<string | null>(null);
|
||||
const [latestBar, setLatestBar] = useState<OHLCVBar | null>(null);
|
||||
const [wsStatus, setWsStatus] = useState<WsStatus>('connecting');
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
@@ -117,13 +120,17 @@ export function useStompChartData(
|
||||
/** 1m 봉 volume 스냅샷 — 상위 분봉 volume 델타 계산용 */
|
||||
const last1mVolRef = useRef<number>(0);
|
||||
const last1mTimeRef = useRef<number>(0);
|
||||
/** 초기 히스토리 로드 완료 전에는 차트 직접 갱신 콜백을 호출하지 않음 */
|
||||
const historyReadyRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (opts.enabled === false) return;
|
||||
let cancelled = false;
|
||||
historyReadyRef.current = false;
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
setBars([]);
|
||||
setBarsMarket(null);
|
||||
barsRef.current = [];
|
||||
last1mVolRef.current = 0;
|
||||
last1mTimeRef.current = 0;
|
||||
@@ -134,6 +141,8 @@ export function useStompChartData(
|
||||
.then(newBars => {
|
||||
if (cancelled) return;
|
||||
barsRef.current = newBars;
|
||||
historyReadyRef.current = newBars.length > 0;
|
||||
setBarsMarket(market);
|
||||
setBars(newBars);
|
||||
setLatestBar(newBars[newBars.length - 1] ?? null);
|
||||
lastTimeRef.current = newBars[newBars.length - 1]?.time ?? 0;
|
||||
@@ -159,10 +168,11 @@ export function useStompChartData(
|
||||
|
||||
const pushBar = (bar: OHLCVBar) => {
|
||||
const current = barsRef.current;
|
||||
const notifyChart = historyReadyRef.current;
|
||||
if (current.length === 0) {
|
||||
barsRef.current = [bar];
|
||||
setLatestBar(bar);
|
||||
optsRef.current.onNewCandle(bar);
|
||||
if (notifyChart) optsRef.current.onNewCandle(bar);
|
||||
lastTimeRef.current = bar.time;
|
||||
return;
|
||||
}
|
||||
@@ -170,16 +180,16 @@ export function useStompChartData(
|
||||
if (bar.time === last.time) {
|
||||
barsRef.current[current.length - 1] = bar;
|
||||
setLatestBar(bar);
|
||||
optsRef.current.onTickUpdate(bar);
|
||||
if (notifyChart) optsRef.current.onTickUpdate(bar);
|
||||
} else if (bar.time > last.time) {
|
||||
barsRef.current = [...current, bar];
|
||||
setLatestBar(bar);
|
||||
optsRef.current.onNewCandle(bar);
|
||||
if (notifyChart) optsRef.current.onNewCandle(bar);
|
||||
} else {
|
||||
const patched = { ...bar, time: last.time };
|
||||
barsRef.current[current.length - 1] = patched;
|
||||
setLatestBar(patched);
|
||||
optsRef.current.onTickUpdate(patched);
|
||||
if (notifyChart) optsRef.current.onTickUpdate(patched);
|
||||
}
|
||||
lastTimeRef.current = bar.time;
|
||||
};
|
||||
@@ -255,12 +265,15 @@ export function useStompChartData(
|
||||
|
||||
setWsStatus('connecting');
|
||||
setError(null);
|
||||
historyReadyRef.current = false;
|
||||
last1mVolRef.current = 0;
|
||||
last1mTimeRef.current = 0;
|
||||
void pinChartWatch(market, STOMP_TICK_CANDLE_TYPE);
|
||||
|
||||
const topic = `/sub/charts/${market}/${STOMP_TICK_CANDLE_TYPE}`;
|
||||
let alive = true;
|
||||
const unsub = subscribeStompTopic(topic, msg => {
|
||||
if (!alive) return;
|
||||
setWsStatus('connected');
|
||||
const data = parseStompJson<StompCandlePayload>(msg);
|
||||
if (data?.time == null || typeof data.time !== 'number') return;
|
||||
@@ -270,11 +283,12 @@ export function useStompChartData(
|
||||
const t = window.setTimeout(() => setWsStatus('connected'), 800);
|
||||
|
||||
return () => {
|
||||
alive = false;
|
||||
window.clearTimeout(t);
|
||||
unsub();
|
||||
setWsStatus('disconnected');
|
||||
};
|
||||
}, [market, timeframe, opts.enabled, applyCandle]);
|
||||
|
||||
return { bars, latestBar, wsStatus, isLoading, error };
|
||||
return { bars, barsMarket, latestBar, wsStatus, isLoading, error };
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ interface UpbitDataOptions {
|
||||
interface UseUpbitDataReturn {
|
||||
/** 초기 200개 캔들 (심볼/타임프레임 변경 시에만 갱신) */
|
||||
bars: OHLCVBar[];
|
||||
/** bars 가 어느 종목 기준인지 (로딩 중·전환 직후 null) */
|
||||
barsMarket: string | null;
|
||||
/** 현재 진행 중인 캔들의 최신 스냅샷 (UI 표시용) */
|
||||
latestBar: OHLCVBar | null;
|
||||
wsStatus: WsStatus;
|
||||
@@ -56,6 +58,7 @@ export function useUpbitData(
|
||||
): UseUpbitDataReturn {
|
||||
// bars = 초기 FETCH_COUNT개 (REST), 실시간 수신 시 변경 안 함 → TradingChart setData 재호출 방지
|
||||
const [bars, setBars] = useState<OHLCVBar[]>([]);
|
||||
const [barsMarket, setBarsMarket] = useState<string | null>(null);
|
||||
const [latestBar, setLatestBar] = useState<OHLCVBar | null>(null);
|
||||
const [wsStatus, setWsStatus] = useState<WsStatus>('connecting');
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
@@ -76,6 +79,7 @@ export function useUpbitData(
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
setBars([]);
|
||||
setBarsMarket(null);
|
||||
setLatestBar(null);
|
||||
barsRef.current = [];
|
||||
|
||||
@@ -92,6 +96,7 @@ export function useUpbitData(
|
||||
.then(newBars => {
|
||||
if (cancelled) return;
|
||||
barsRef.current = newBars;
|
||||
setBarsMarket(market);
|
||||
setBars(newBars);
|
||||
setLatestBar(newBars[newBars.length - 1] ?? null);
|
||||
setIsLoading(false);
|
||||
@@ -169,5 +174,5 @@ export function useUpbitData(
|
||||
return () => client.destroy();
|
||||
}, [market, timeframe, handleMessage, opts.enabled]);
|
||||
|
||||
return { bars, latestBar, wsStatus, isLoading, error };
|
||||
return { bars, barsMarket, latestBar, wsStatus, isLoading, error };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user