/** * useDeepAnalysisData Hook * * 管理深度分析模块的数据获取逻辑: * - 按 Tab 懒加载数据 * - 已加载数据缓存,避免重复请求 * - 竞态条件处理 */ import { useState, useCallback, useRef, useEffect } from 'react'; import axios from '@utils/axiosConfig'; import { logger } from '@utils/logger'; import type { ApiKey, ApiLoadingState, DataState, UseDeepAnalysisDataReturn, } from '../types'; import { TAB_API_MAP } from '../types'; /** API 端点映射 */ const API_ENDPOINTS: Record = { comprehensive: '/api/company/comprehensive-analysis', valueChain: '/api/company/value-chain-analysis', keyFactors: '/api/company/key-factors-timeline', industryRank: '/api/financial/industry-rank', }; /** 初始数据状态 */ const initialDataState: DataState = { comprehensive: null, valueChain: null, keyFactors: null, industryRank: null, }; /** 初始 loading 状态 */ const initialLoadingState: ApiLoadingState = { comprehensive: false, valueChain: false, keyFactors: false, industryRank: false, }; /** * 深度分析数据 Hook * * @param stockCode 股票代码 * @returns 数据、loading 状态、加载函数 */ export const useDeepAnalysisData = (stockCode: string): UseDeepAnalysisDataReturn => { // 数据状态 const [data, setData] = useState(initialDataState); // Loading 状态 const [loading, setLoading] = useState(initialLoadingState); // 已加载的接口记录 const loadedApisRef = useRef>({ comprehensive: false, valueChain: false, keyFactors: false, industryRank: false, }); // 当前 stockCode(用于竞态条件检测) const currentStockCodeRef = useRef(stockCode); /** * 加载指定 API 数据 */ const loadApiData = useCallback( async (apiKey: ApiKey) => { if (!stockCode) return; // 已加载则跳过 if (loadedApisRef.current[apiKey]) return; // 设置 loading setLoading((prev) => ({ ...prev, [apiKey]: true })); try { const endpoint = `${API_ENDPOINTS[apiKey]}/${stockCode}`; const { data: response } = await axios.get(endpoint); // 检查 stockCode 是否已变更(防止竞态) if (currentStockCodeRef.current !== stockCode) return; if (response.success) { setData((prev) => ({ ...prev, [apiKey]: response.data })); loadedApisRef.current[apiKey] = true; } } catch (err) { logger.error('DeepAnalysis', `loadApiData:${apiKey}`, err, { stockCode }); } finally { // 清除 loading(再次检查 stockCode) if (currentStockCodeRef.current === stockCode) { setLoading((prev) => ({ ...prev, [apiKey]: false })); } } }, [stockCode] ); /** * 根据 Tab 加载对应数据 */ const loadTabData = useCallback( (tabKey: string) => { const apiKey = TAB_API_MAP[tabKey]; if (apiKey) { loadApiData(apiKey); } }, [loadApiData] ); /** * 重置所有数据 */ const resetData = useCallback(() => { setData(initialDataState); setLoading(initialLoadingState); loadedApisRef.current = { comprehensive: false, valueChain: false, keyFactors: false, industryRank: false, }; }, []); // stockCode 变更时重置并加载默认数据 useEffect(() => { if (stockCode) { currentStockCodeRef.current = stockCode; resetData(); // 只加载默认 Tab(comprehensive) loadApiData('comprehensive'); } }, [stockCode, loadApiData, resetData]); return { data, loading, loadTabData, resetData, }; }; export default useDeepAnalysisData;