Files
auto-trade/features/trade/hooks/useOrderbookSubscription.ts

64 lines
2.2 KiB
TypeScript

import { useRef, useEffect } from "react";
import type { KisRuntimeCredentials } from "@/features/settings/store/use-kis-runtime-store";
import type { DashboardStockOrderBookResponse } from "@/features/trade/types/trade.types";
import { useKisWebSocketStore } from "@/features/kis-realtime/stores/kisWebSocketStore";
import {
parseKisRealtimeOrderbook,
resolveOrderBookTrIds,
} from "@/features/trade/utils/kisRealtimeUtils";
import type { DomesticKisSession } from "@/lib/kis/domestic-market-session";
interface UseOrderbookSubscriptionParams {
symbol: string | undefined; // orderBookSymbol
isVerified: boolean;
credentials: KisRuntimeCredentials | null;
marketSession: DomesticKisSession;
onOrderBookMessage?: (data: DashboardStockOrderBookResponse) => void;
}
/**
* @description 실시간 호가(Orderbook) 구독 로직을 담당하는 훅입니다.
* - 호가 데이터는 빈도가 매우 높으므로 별도의 상태(state)에 저장하지 않고,
* - 콜백 함수(onOrderBookMessage)를 통해 상위 컴포넌트로 데이터를 직접 전달합니다.
* - 이를 통해 불필요한 리렌더링을 방지합니다.
*/
export function useOrderbookSubscription({
symbol,
isVerified,
credentials,
marketSession,
onOrderBookMessage,
}: UseOrderbookSubscriptionParams) {
const { subscribe, connect } = useKisWebSocketStore();
const onOrderBookMessageRef = useRef(onOrderBookMessage);
useEffect(() => {
onOrderBookMessageRef.current = onOrderBookMessage;
}, [onOrderBookMessage]);
useEffect(() => {
if (!symbol || !isVerified || !credentials) return;
connect();
const trIds = resolveOrderBookTrIds(credentials.tradingEnv, marketSession);
const unsubscribers: Array<() => void> = [];
const handleOrderBookMessage = (data: string) => {
const ob = parseKisRealtimeOrderbook(data, symbol);
if (ob) {
ob.tradingEnv = credentials.tradingEnv;
onOrderBookMessageRef.current?.(ob);
}
};
for (const trId of trIds) {
unsubscribers.push(subscribe(trId, symbol, handleOrderBookMessage));
}
return () => {
unsubscribers.forEach((unsub) => unsub());
};
}, [symbol, isVerified, credentials, marketSession, connect, subscribe]);
}