From 1d5efd88b2472809e75622e57704f8e802970c11 Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Thu, 30 Oct 2025 13:06:48 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=9B=E5=BB=BA=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E4=B8=AA=20Hook=20-=20useStockMonitoring.js=EF=BC=88=E5=AE=9E?= =?UTF-8?q?=E6=97=B6=E7=9B=91=E6=8E=A7=E5=8A=9F=E8=83=BD=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hooks/useStockMonitoring.js | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 src/views/Community/components/StockDetailPanel/hooks/useStockMonitoring.js diff --git a/src/views/Community/components/StockDetailPanel/hooks/useStockMonitoring.js b/src/views/Community/components/StockDetailPanel/hooks/useStockMonitoring.js new file mode 100644 index 00000000..9f988c4f --- /dev/null +++ b/src/views/Community/components/StockDetailPanel/hooks/useStockMonitoring.js @@ -0,0 +1,159 @@ +// src/views/Community/components/StockDetailPanel/hooks/useStockMonitoring.js +import { useSelector, useDispatch } from 'react-redux'; +import { useState, useEffect, useRef, useCallback } from 'react'; +import { fetchStockQuotes } from '../../../../../store/slices/stockSlice'; +import { message } from 'antd'; +import { logger } from '../../../../../utils/logger'; + +/** + * 股票实时监控 Hook + * 提供定时刷新股票行情的功能 + * + * @param {Array} stocks - 股票列表 + * @param {string} eventTime - 事件时间 + * @param {number} interval - 刷新间隔(毫秒),默认 5000ms + * @returns {Object} 监控状态和控制方法 + */ +export const useStockMonitoring = (stocks = [], eventTime = null, interval = 5000) => { + const dispatch = useDispatch(); + const [isMonitoring, setIsMonitoring] = useState(false); + const monitoringIntervalRef = useRef(null); + + // 从 Redux 获取行情数据和加载状态 + const quotes = useSelector(state => state.stock.quotes); + const quotesLoading = useSelector(state => state.stock.loading.quotes); + + /** + * 执行一次行情更新 + */ + const updateQuotes = useCallback(() => { + if (stocks.length === 0) { + logger.warn('useStockMonitoring', '股票列表为空,跳过更新'); + return; + } + + const codes = stocks.map(s => s.stock_code); + logger.debug('useStockMonitoring', '更新行情数据', { + stockCount: codes.length, + eventTime, + timestamp: new Date().toISOString() + }); + + dispatch(fetchStockQuotes({ codes, eventTime })); + }, [dispatch, stocks, eventTime]); + + /** + * 开启实时监控 + */ + const startMonitoring = useCallback(() => { + if (isMonitoring) { + logger.warn('useStockMonitoring', '监控已经在运行中'); + return; + } + + if (stocks.length === 0) { + message.warning('暂无股票数据,无法开启监控'); + return; + } + + logger.info('useStockMonitoring', '开启实时监控', { + interval, + stockCount: stocks.length + }); + + setIsMonitoring(true); + message.success(`已开启实时监控,每${interval / 1000}秒自动更新`); + + // 立即执行一次 + updateQuotes(); + }, [isMonitoring, stocks, interval, updateQuotes]); + + /** + * 停止实时监控 + */ + const stopMonitoring = useCallback(() => { + if (!isMonitoring) { + return; + } + + logger.info('useStockMonitoring', '停止实时监控'); + + setIsMonitoring(false); + message.info('已停止实时监控'); + }, [isMonitoring]); + + /** + * 切换监控状态 + */ + const toggleMonitoring = useCallback(() => { + if (isMonitoring) { + stopMonitoring(); + } else { + startMonitoring(); + } + }, [isMonitoring, startMonitoring, stopMonitoring]); + + /** + * 手动刷新一次 + */ + const manualRefresh = useCallback(() => { + logger.debug('useStockMonitoring', '手动刷新行情'); + updateQuotes(); + }, [updateQuotes]); + + // 监控定时器效果 + useEffect(() => { + // 清理旧的定时器 + if (monitoringIntervalRef.current) { + clearInterval(monitoringIntervalRef.current); + monitoringIntervalRef.current = null; + } + + if (isMonitoring && stocks.length > 0) { + // 设置定时器 + monitoringIntervalRef.current = setInterval(() => { + updateQuotes(); + }, interval); + + logger.debug('useStockMonitoring', '定时器已设置', { + interval, + stockCount: stocks.length + }); + } + + // 清理函数 + return () => { + if (monitoringIntervalRef.current) { + clearInterval(monitoringIntervalRef.current); + monitoringIntervalRef.current = null; + logger.debug('useStockMonitoring', '定时器已清理'); + } + }; + }, [isMonitoring, stocks.length, interval]); // 注意:不依赖 updateQuotes,避免重复创建定时器 + + // 组件卸载时自动停止监控 + useEffect(() => { + return () => { + if (isMonitoring) { + logger.debug('useStockMonitoring', '组件卸载,自动停止监控'); + setIsMonitoring(false); + } + }; + }, []); // 只在卸载时执行 + + return { + // 状态 + isMonitoring, + quotes, + quotesLoading, + + // 控制方法 + startMonitoring, + stopMonitoring, + toggleMonitoring, + manualRefresh, + + // 工具方法 + setIsMonitoring + }; +};