feat: 创建第三个 Hook - useStockMonitoring.js(实时监控功能)

This commit is contained in:
zdl
2025-10-30 13:06:48 +08:00
parent 19a8866305
commit 1d5efd88b2

View File

@@ -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
};
};