refactor: 프론트엔드 TypeScript 타입 안전성 및 커스텀 훅 분리
- types/trading.ts: 중앙 타입 정의 (CandleData, Position, Trade 등) - useMarketData.ts: 실시간 시세 처리 + 500ms 쓰로틀링 - usePortfolioData.ts: React Query 기반 포트폴리오 데이터 훅 - useTradeActions.ts: 매매 실행 액션 훅 - useWebSocket.ts: pong timeout 10초 감지 (좀비 연결 방지) - TradingChart.tsx: @ts-nocheck 제거, CandleData 타입 적용 - PortfolioPanel/RecommendationPanel: any → 구체적 타입 교체 - Dashboard.tsx: 상태 관리 로직을 커스텀 훅으로 이전 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
65
frontend/src/hooks/useMarketData.ts
Normal file
65
frontend/src/hooks/useMarketData.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { useEffect, useState, useRef, useCallback } from 'react'
|
||||
|
||||
export const useMarketData = (
|
||||
selectedStock: string,
|
||||
portfolio: any[] | undefined
|
||||
) => {
|
||||
// Live prices with throttling to prevent excessive re-renders
|
||||
const [livePrices, setLivePrices] = useState<Record<string, number>>({})
|
||||
const [liveQuote, setLiveQuote] = useState<any>(null)
|
||||
|
||||
// Throttle ref: track last update time per stock
|
||||
const lastPriceUpdateRef = useRef<Record<string, number>>({})
|
||||
const throttleDelayMs = 500 // Max 2-3 price updates per second (500ms = 2/sec)
|
||||
|
||||
// Handle market updates (tick data) with throttling
|
||||
const handleMarketUpdate = useCallback((data: unknown) => {
|
||||
const d = data as any
|
||||
if (d?._type === 'tick' && d.stock_code && d.price != null) {
|
||||
const now = Date.now()
|
||||
const lastUpdate =
|
||||
lastPriceUpdateRef.current[d.stock_code] ?? 0
|
||||
|
||||
// Only update if throttle delay has passed
|
||||
if (now - lastUpdate >= throttleDelayMs) {
|
||||
setLivePrices((prev) => ({
|
||||
...prev,
|
||||
[d.stock_code]: d.price,
|
||||
}))
|
||||
lastPriceUpdateRef.current[d.stock_code] = now
|
||||
}
|
||||
} else if (
|
||||
d?._type === 'quote' &&
|
||||
d.stock_code === selectedStock
|
||||
) {
|
||||
setLiveQuote(d)
|
||||
}
|
||||
}, [selectedStock])
|
||||
|
||||
|
||||
// Initialize live prices from portfolio
|
||||
useEffect(() => {
|
||||
if (!portfolio) return
|
||||
setLivePrices((prev) => {
|
||||
const next = { ...prev }
|
||||
portfolio.forEach((s: any) => {
|
||||
if (s.current_price && !next[s.stock_code]) {
|
||||
next[s.stock_code] = Number(s.current_price)
|
||||
}
|
||||
})
|
||||
return next
|
||||
})
|
||||
}, [portfolio])
|
||||
|
||||
// Clear live quote when selected stock changes
|
||||
useEffect(() => {
|
||||
setLiveQuote(null)
|
||||
}, [selectedStock])
|
||||
|
||||
|
||||
return {
|
||||
livePrices,
|
||||
liveQuote,
|
||||
handleMarketUpdate,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user