diff --git a/frontend/src/hooks/useTradeNotificationSignalSnapshot.ts b/frontend/src/hooks/useTradeNotificationSignalSnapshot.ts index 501a69b..3e8ebeb 100644 --- a/frontend/src/hooks/useTradeNotificationSignalSnapshot.ts +++ b/frontend/src/hooks/useTradeNotificationSignalSnapshot.ts @@ -2,7 +2,7 @@ * 매매 시그널 알림 목록 행 — 종목×전략 실시간 신호 스냅샷 (가상매매 카드 요약형과 동일 소스) */ import { useCallback, useEffect, useRef, useState } from 'react'; -import type { StrategyDto } from '../utils/backendApi'; +import { isStrategyMissingOnServer, loadStrategy, type StrategyDto } from '../utils/backendApi'; import { fetchLiveSnapshot, type VirtualIndicatorSnapshot, @@ -19,6 +19,8 @@ export function useTradeNotificationSignalSnapshot( const [loading, setLoading] = useState(false); const emptyRetryRef = useRef(0); const genRef = useRef(0); + /** strategy prop 이 undefined 일 때 직접 로드한 전략 캐시 */ + const fallbackStrategyRef = useRef(null); const refresh = useCallback(async () => { if (!enabled || strategyId == null) { @@ -29,8 +31,27 @@ export function useTradeNotificationSignalSnapshot( const gen = ++genRef.current; setLoading(true); + + // strategy prop 이 undefined 면 내부에서 직접 로드해 baseRows 를 확보한다. + // 이렇게 하면 strategy 가 늦게 주입되어도 조건 목록이 즉시 표시된다. + let effectiveStrategy = strategy; + if (!effectiveStrategy) { + if (fallbackStrategyRef.current) { + effectiveStrategy = fallbackStrategyRef.current; + } else if (!isStrategyMissingOnServer(strategyId)) { + try { + const loaded = await loadStrategy(strategyId); + if (loaded) { + fallbackStrategyRef.current = loaded; + effectiveStrategy = loaded; + } + } catch { /* ignore */ } + if (gen !== genRef.current) return; + } + } + const pinFirst = emptyRetryRef.current === 0; - const snap = await fetchLiveSnapshot(market, strategyId, strategy, pinFirst); + const snap = await fetchLiveSnapshot(market, strategyId, effectiveStrategy, pinFirst); if (gen !== genRef.current) return; if (snap && snap.rows.length > 0) { @@ -40,14 +61,7 @@ export function useTradeNotificationSignalSnapshot( } setSnapshot(snap ?? undefined); - - // strategy 가 아직 로드되지 않았고 데이터도 없으면 loading 유지: - // strategy 가 로드되면 refresh 가 갱신되어 재시도하며, 그때 조건이 표시된다. - if (!snap && strategy === undefined) { - setLoading(true); - } else { - setLoading(false); - } + setLoading(false); }, [market, strategyId, strategy, enabled]); useEffect(() => { @@ -58,6 +72,7 @@ export function useTradeNotificationSignalSnapshot( return; } emptyRetryRef.current = 0; + fallbackStrategyRef.current = null; // strategy prop 변경 시 캐시 초기화 setLoading(true); // 활성화 즉시 로딩 표시 void refresh(); const id = window.setInterval(() => void refresh(), pollMs);