| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- '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<TradeData[]>([]);
- const tradesRef = useRef<TradeData[]>([]);
- const updateTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
- // REST 초기 로드
- useEffect(() => {
- if (!market) {
- return;
- }
- setTrades([]);
- tradesRef.current = [];
- const load = async () => {
- try {
- const res = await fetchApi<TradeRestData[]>(`/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;
- }
|