'use client'; import { useEffect, useState, useCallback, useRef } from 'react'; import { useSignalRContext } from '@/contexts/signalrProvider'; import { fetchApi } from '@/lib/utils/client'; import type { TradeData, TradeRestData } from '@/types/crypto'; const MAX_TRADES = 100; export default function useTrades(market: string) { const { cryptoConnection, cryptoConnected } = useSignalRContext(); const [trades, setTrades] = useState([]); const tradesRef = useRef([]); const updateTimerRef = useRef | null>(null); // REST 초기 로드 useEffect(() => { if (!market) { return; } setTrades([]); tradesRef.current = []; const load = async () => { try { const res = await fetchApi(`/api/crypto/${market}/trades?count=50`); if (res.success && res.data) { const mapped: TradeData[] = res.data.map((t) => ({ market, symbol: market.split('-')[1] || '', tradePrice: t.tradePrice, tradeVolume: t.tradeVolume, askBid: t.askBid, prevClosingPrice: t.prevClosingPrice, change: '', changePrice: t.changePrice, tradeDate: '', tradeTime: '', tradeTimestamp: t.timestamp, sequentialId: t.sequentialId, timestamp: t.timestamp, streamType: 'SNAPSHOT', bestAskPrice: 0, bestAskSize: 0, bestBidPrice: 0, bestBidSize: 0, })); tradesRef.current = mapped; setTrades(mapped); } } catch (error) { console.error('Failed to load trades:', error); } }; load(); }, [market]); // 배치 업데이트 const scheduleUpdate = useCallback(() => { if (updateTimerRef.current) { return; } updateTimerRef.current = setTimeout(() => { setTrades([...tradesRef.current]); updateTimerRef.current = null; }, 200); }, []); // SignalR 실시간 업데이트 const handleTrade = useCallback((data: TradeData) => { if (data.market === market) { tradesRef.current = [data, ...tradesRef.current].slice(0, MAX_TRADES); scheduleUpdate(); } }, [market, scheduleUpdate]); useEffect(() => { if (!cryptoConnection || !cryptoConnected) { return; } cryptoConnection.on('ReceiveTrade', handleTrade); return () => { cryptoConnection.off('ReceiveTrade', handleTrade); if (updateTimerRef.current) { clearTimeout(updateTimerRef.current); updateTimerRef.current = null; } }; }, [cryptoConnection, cryptoConnected, handleTrade]); return trades; }