From 9e271747da6ba3c4ad6917e1513e24441b7d0c1c Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Mon, 22 Dec 2025 12:15:39 +0800 Subject: [PATCH] =?UTF-8?q?perf(MarketDataView):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E7=8A=B6=E6=80=81=EF=BC=8C=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E9=AA=A8=E6=9E=B6=E5=B1=8F=E9=81=BF=E5=85=8D=E5=B8=83=E5=B1=80?= =?UTF-8?q?=E8=B7=B3=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - useMarketData: 新增 hasLoaded 状态,优化首次加载 loading 逻辑 - 导出 SummaryCardSkeleton 组件用于概览卡片占位 - MarketDataView: 使用骨架屏替代空白占位 - DeepAnalysisTab: 使用 skeleton 变体替代 spinner 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../CompanyOverview/DeepAnalysisTab/index.tsx | 2 +- .../components/MarketDataSkeleton.tsx | 2 +- .../MarketDataView/components/index.ts | 2 +- .../MarketDataView/hooks/useMarketData.ts | 24 ++++++++++++------- .../components/MarketDataView/index.tsx | 16 ++++++------- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/views/Company/components/CompanyOverview/DeepAnalysisTab/index.tsx b/src/views/Company/components/CompanyOverview/DeepAnalysisTab/index.tsx index fa2642d4..a9dd6181 100644 --- a/src/views/Company/components/CompanyOverview/DeepAnalysisTab/index.tsx +++ b/src/views/Company/components/CompanyOverview/DeepAnalysisTab/index.tsx @@ -77,7 +77,7 @@ const DeepAnalysisTab: React.FC = ({ themePreset="blackGold" size="sm" /> - + ); diff --git a/src/views/Company/components/MarketDataView/components/MarketDataSkeleton.tsx b/src/views/Company/components/MarketDataView/components/MarketDataSkeleton.tsx index 67ff83c4..a2c5daae 100644 --- a/src/views/Company/components/MarketDataView/components/MarketDataSkeleton.tsx +++ b/src/views/Company/components/MarketDataView/components/MarketDataSkeleton.tsx @@ -136,5 +136,5 @@ const MarketDataSkeleton: React.FC = memo(() => ( MarketDataSkeleton.displayName = 'MarketDataSkeleton'; -export { MarketDataSkeleton }; +export { MarketDataSkeleton, SummaryCardSkeleton }; export default MarketDataSkeleton; diff --git a/src/views/Company/components/MarketDataView/components/index.ts b/src/views/Company/components/MarketDataView/components/index.ts index 1a854d60..91b880e7 100644 --- a/src/views/Company/components/MarketDataView/components/index.ts +++ b/src/views/Company/components/MarketDataView/components/index.ts @@ -5,4 +5,4 @@ export { default as ThemedCard } from './ThemedCard'; export { default as MarkdownRenderer } from './MarkdownRenderer'; export { default as StockSummaryCard } from './StockSummaryCard'; export { default as AnalysisModal, AnalysisContent } from './AnalysisModal'; -export { MarketDataSkeleton } from './MarketDataSkeleton'; +export { MarketDataSkeleton, SummaryCardSkeleton } from './MarketDataSkeleton'; diff --git a/src/views/Company/components/MarketDataView/hooks/useMarketData.ts b/src/views/Company/components/MarketDataView/hooks/useMarketData.ts index 6231b8b3..eaf6b751 100644 --- a/src/views/Company/components/MarketDataView/hooks/useMarketData.ts +++ b/src/views/Company/components/MarketDataView/hooks/useMarketData.ts @@ -33,8 +33,9 @@ export const useMarketData = ( period: number = DEFAULT_PERIOD ): UseMarketDataReturn => { // 主数据状态 - const [loading, setLoading] = useState(false); + const [loading, setLoading] = useState(true); const [tradeLoading, setTradeLoading] = useState(false); + const [hasLoaded, setHasLoaded] = useState(false); const [summary, setSummary] = useState(null); const [tradeData, setTradeData] = useState([]); const [fundingData, setFundingData] = useState([]); @@ -153,15 +154,17 @@ export const useMarketData = ( if (loadedTradeData.length > 0) { loadRiseAnalysis(loadedTradeData); } + + setLoading(false); + setHasLoaded(true); } catch (error) { - // 取消请求不作为错误处理 - if (isCancelError(error)) return; - logger.error('useMarketData', 'loadCoreData', error, { stockCode, period }); - } finally { - // 只有当前请求没有被取消时才设置 loading 状态 - if (!controller.signal.aborted) { - setLoading(false); + // 请求被取消时,不更新任何状态 + if (isCancelError(error)) { + return; } + logger.error('useMarketData', 'loadCoreData', error, { stockCode, period }); + setLoading(false); + setHasLoaded(true); } }, [stockCode, period, loadRiseAnalysis]); @@ -363,8 +366,11 @@ export const useMarketData = ( }; }, []); + // 派生 loading 状态:stockCode 存在但尚未完成首次加载时,视为 loading + const isLoading = loading || (!!stockCode && !hasLoaded); + return { - loading, + loading: isLoading, tradeLoading, summary, tradeData, diff --git a/src/views/Company/components/MarketDataView/index.tsx b/src/views/Company/components/MarketDataView/index.tsx index 51030aaf..e4140a54 100644 --- a/src/views/Company/components/MarketDataView/index.tsx +++ b/src/views/Company/components/MarketDataView/index.tsx @@ -22,6 +22,7 @@ import { useMarketData } from './hooks/useMarketData'; import { ThemedCard, StockSummaryCard, + SummaryCardSkeleton, AnalysisModal, AnalysisContent, } from './components'; @@ -89,13 +90,12 @@ const MarketDataView: React.FC = ({ stockCode: propStockCod } }, [propStockCode, stockCode]); - // 首次渲染时加载默认 Tab(融资融券)的数据 + // 首次挂载时加载默认 Tab(融资融券)的数据 + // 注意:SubTabContainer 的 onChange 只在切换时触发,首次渲染不会触发 useEffect(() => { - // 默认 Tab 是融资融券(index 0) - if (activeTab === 0) { - loadDataByType('funding'); - } - }, [loadDataByType, activeTab]); + loadDataByType('funding'); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); // 只在首次挂载时执行 // 处理图表点击事件 const handleChartClick = useCallback( @@ -137,8 +137,8 @@ const MarketDataView: React.FC = ({ stockCode: propStockCod - {/* 股票概览 */} - {summary && } + {/* 股票概览 - 未加载时显示骨架屏占位,避免布局跳动 */} + {summary ? : } {/* 交易数据 - 日K/分钟K线(独立显示在 Tab 上方) */}