import { useCallback, useRef, useState } from "react"; import type { KisRuntimeCredentials } from "@/features/dashboard/store/use-kis-runtime-store"; import type { DashboardStockSearchItem } from "@/features/dashboard/types/dashboard.types"; import { fetchStockSearch } from "@/features/dashboard/apis/kis-stock.api"; export function useStockSearch() { const [keyword, setKeyword] = useState("삼성전자"); const [searchResults, setSearchResults] = useState< DashboardStockSearchItem[] >([]); const [error, setError] = useState(null); const [isSearching, setIsSearching] = useState(false); const requestIdRef = useRef(0); const abortRef = useRef(null); const loadSearch = useCallback(async (query: string) => { const requestId = ++requestIdRef.current; const controller = new AbortController(); abortRef.current?.abort(); abortRef.current = controller; setIsSearching(true); setError(null); try { const data = await fetchStockSearch(query, controller.signal); if (requestId === requestIdRef.current) { setSearchResults(data.items); } return data.items; } catch (err) { if (controller.signal.aborted) { return []; } if (requestId === requestIdRef.current) { setError( err instanceof Error ? err.message : "종목 검색 중 오류가 발생했습니다.", ); } return []; } finally { if (requestId === requestIdRef.current) { setIsSearching(false); } } }, []); const search = useCallback( (query: string, credentials: KisRuntimeCredentials | null) => { if (!credentials) { setError("API 키 검증이 필요합니다."); setSearchResults([]); setIsSearching(false); return; } const trimmed = query.trim(); if (!trimmed) { abortRef.current?.abort(); setSearchResults([]); setError(null); setIsSearching(false); return; } void loadSearch(trimmed); }, [loadSearch], ); const clearSearch = useCallback(() => { abortRef.current?.abort(); setSearchResults([]); setError(null); setIsSearching(false); }, []); return { keyword, setKeyword, searchResults, setSearchResults, error, setError, isSearching, search, clearSearch, }; }