전략편집기 화면접속 시 에러 수정

This commit is contained in:
Macbook
2026-05-31 23:36:33 +09:00
parent 2f5316d172
commit a34b49c23a
4 changed files with 96 additions and 29 deletions
+67 -24
View File
@@ -36,6 +36,8 @@ export interface MarketInfo {
}
export interface UseMarketTickerOptions {
/** false — REST·WS 중지(전략편집기 등), 캐시된 tickers 유지 */
enabled?: boolean;
/** 우선 종목만 먼저 로드 (기본: 마켓 패널 닫힘) */
lite?: boolean;
priorityMarkets?: string[];
@@ -147,6 +149,7 @@ function subscribeTickerWs(
}
export function useMarketTicker(opts: UseMarketTickerOptions = {}) {
const enabled = opts.enabled ?? true;
const loadFull = opts.loadFull ?? false;
const isMobileLite = opts.lite ?? false;
const priorityList = mergePriorityMarkets(opts.getPriorityMarkets?.() ?? opts.priorityMarkets);
@@ -209,12 +212,14 @@ export function useMarketTicker(opts: UseMarketTickerOptions = {}) {
}, [applyRawList, clearPoll, isMobileLite]);
const loadTickersFor = useCallback(async (markets: string[]) => {
if (!enabled) return [];
const rawList = await fetchTickersThrottled(markets);
if (mountedRef.current && rawList.length > 0) applyRawList(rawList);
return rawList;
}, [applyRawList]);
}, [applyRawList, enabled]);
const runFullTickerLoad = useCallback(async () => {
if (!enabled) return;
const all = marketListRef.current;
if (all.length === 0 || fullLoadedRef.current) return;
@@ -231,19 +236,57 @@ export function useMarketTicker(opts: UseMarketTickerOptions = {}) {
fullLoadedRef.current = true;
attachWs(wsTickerMarkets(all, priorityList));
startPoll(all);
}, [isMobileLite, loadTickersFor, attachWs, startPoll, priorityList]);
}, [enabled, isMobileLite, loadTickersFor, attachWs, startPoll, priorityList]);
// 1) 마켓 목록 + 우선 종목 ticker (마운트 1회)
const pauseFeed = useCallback(() => {
destroyWsRef.current?.();
destroyWsRef.current = null;
clearPoll();
}, [clearPoll]);
const resumeFeed = useCallback(() => {
const all = marketListRef.current;
if (all.length === 0) return;
attachWs(wsTickerMarkets(all, priorityList));
if (loadFull && fullLoadedRef.current && !isMobileLite) {
startPoll(all);
}
}, [attachWs, priorityList, loadFull, isMobileLite, startPoll]);
// 마운트 생명주기
useEffect(() => {
mountedRef.current = true;
fullLoadedRef.current = false;
initDoneRef.current = false;
return () => {
mountedRef.current = false;
pauseFeed();
};
}, [pauseFeed]);
const enabledRef = useRef(enabled);
enabledRef.current = enabled;
const priorityListRef = useRef(priorityList);
priorityListRef.current = priorityList;
const loadFullRef = useRef(loadFull);
loadFullRef.current = loadFull;
// enabled: 비차트 화면(전략편집기 등)에서 REST·WS 중지
useEffect(() => {
if (!enabled) {
pauseFeed();
if (initDoneRef.current) setLoading(false);
return;
}
if (initDoneRef.current) {
resumeFeed();
return;
}
let cancelled = false;
(async () => {
let infos: MarketInfo[] = [];
try { infos = await fetchAllMarkets(); }
catch { /* ignore */ }
if (!mountedRef.current) return;
if (cancelled || !mountedRef.current || !enabledRef.current) return;
infos.forEach(m => marketInfoMapRef.current.set(m.market, m));
setMarketInfos(infos);
@@ -252,40 +295,40 @@ export function useMarketTicker(opts: UseMarketTickerOptions = {}) {
if (!allMarkets.includes('KRW-USDT')) allMarkets.push('KRW-USDT');
marketListRef.current = allMarkets;
await loadTickersFor(priorityList);
if (!mountedRef.current) return;
const pri = mergePriorityMarkets(
opts.getPriorityMarkets?.() ?? opts.priorityMarkets,
);
if (!enabledRef.current) return;
const rawList = await fetchTickersThrottled(pri);
if (cancelled || !mountedRef.current || !enabledRef.current) return;
if (rawList.length > 0) applyRawList(rawList);
setLoading(false);
initDoneRef.current = true;
attachWs(wsTickerMarkets(allMarkets, priorityList));
attachWs(wsTickerMarkets(allMarkets, pri));
if (loadFull && !isMobileLite) {
if (loadFullRef.current && !isMobileLite) {
setTimeout(() => { void runFullTickerLoad(); }, FULL_LOAD_DEFER_MS);
}
})();
return () => {
mountedRef.current = false;
destroyWsRef.current?.();
destroyWsRef.current = null;
clearPoll();
};
// eslint-disable-next-line react-hooks/exhaustive-deps -- init only
}, []);
return () => { cancelled = true; };
// eslint-disable-next-line react-hooks/exhaustive-deps -- enabled 토글·최초 1회만
}, [enabled]);
// 2) 마켓 패널 열림 → 전 종목 (모바일: 백엔드 1회, PC: 지연 후 일괄)
// 마켓 패널 열림 → 전 종목
useEffect(() => {
if (!loadFull || !initDoneRef.current) return;
if (!enabled || !loadFull || !initDoneRef.current) return;
if (fullLoadedRef.current) return;
const delay = isMobileLite ? 300 : FULL_LOAD_DEFER_MS;
const t = setTimeout(() => { void runFullTickerLoad(); }, delay);
return () => clearTimeout(t);
}, [isMobileLite, loadFull, runFullTickerLoad]);
}, [enabled, isMobileLite, loadFull, runFullTickerLoad]);
// 3) 우선 종목 변경 — 디바운스(메뉴·심볼 전환 시 REST 폭주 방지)
// 우선 종목 변경
useEffect(() => {
if (!initDoneRef.current) return;
if (!enabled || !initDoneRef.current) return;
const t = setTimeout(() => {
if (!mountedRef.current) return;
if (!fullLoadedRef.current) void loadTickersFor(priorityList);
@@ -293,7 +336,7 @@ export function useMarketTicker(opts: UseMarketTickerOptions = {}) {
if (all.length > 0) attachWs(wsTickerMarkets(all, priorityList));
}, PRIORITY_DEBOUNCE_MS);
return () => clearTimeout(t);
}, [priorityKey, loadTickersFor, attachWs, priorityList]);
}, [enabled, priorityKey, loadTickersFor, attachWs, priorityList]);
return { tickers, marketInfos, loading, usdRate };
}