// src/hooks/useEventNotifications.js /** * React Hook:用于在组件中订阅事件推送通知 * * 使用示例: * ```jsx * import { useEventNotifications } from 'hooks/useEventNotifications'; * * function MyComponent() { * const { newEvent, isConnected } = useEventNotifications({ * eventType: 'all', * importance: 'all', * onNewEvent: (event) => { * console.log('收到新事件:', event); * // 显示通知... * } * }); * * return
...
; * } * ``` */ import { useEffect, useState, useRef } from 'react'; import { socketService } from '../services/socketService'; import { logger } from '../utils/logger'; export const useEventNotifications = (options = {}) => { const { eventType = 'all', importance = 'all', enabled = true, onNewEvent, } = options; const [isConnected, setIsConnected] = useState(false); const [newEvent, setNewEvent] = useState(null); const [error, setError] = useState(null); const unsubscribeRef = useRef(null); // 使用 ref 存储 onNewEvent 回调,避免因回调函数引用改变导致重新连接 const onNewEventRef = useRef(onNewEvent); // 每次 onNewEvent 改变时更新 ref useEffect(() => { onNewEventRef.current = onNewEvent; }, [onNewEvent]); useEffect(() => { console.log('[useEventNotifications DEBUG] ========== useEffect 执行 =========='); console.log('[useEventNotifications DEBUG] enabled:', enabled); console.log('[useEventNotifications DEBUG] eventType:', eventType); console.log('[useEventNotifications DEBUG] importance:', importance); // 如果禁用,则不订阅 if (!enabled) { console.log('[useEventNotifications DEBUG] ⚠️ 订阅已禁用,跳过'); return; } // 连接状态监听 const handleConnect = () => { console.log('[useEventNotifications DEBUG] ✓ WebSocket 已连接'); logger.info('useEventNotifications', 'WebSocket connected'); setIsConnected(true); setError(null); }; const handleDisconnect = () => { console.log('[useEventNotifications DEBUG] ⚠️ WebSocket 已断开'); logger.warn('useEventNotifications', 'WebSocket disconnected'); setIsConnected(false); }; const handleConnectError = (err) => { console.error('[useEventNotifications ERROR] WebSocket 连接错误:', err); logger.error('useEventNotifications', 'WebSocket connect error', err); setError(err); setIsConnected(false); }; // 监听连接事件(必须在connect之前设置,否则可能错过事件) socketService.on('connect', handleConnect); socketService.on('disconnect', handleDisconnect); socketService.on('connect_error', handleConnectError); // 连接 WebSocket console.log('[useEventNotifications DEBUG] 准备连接 WebSocket...'); logger.info('useEventNotifications', 'Initializing WebSocket connection'); // 先检查是否已经连接 const alreadyConnected = socketService.isConnected(); console.log('[useEventNotifications DEBUG] 当前连接状态:', alreadyConnected); logger.info('useEventNotifications', 'Pre-connection check', { isConnected: alreadyConnected }); if (alreadyConnected) { // 如果已经连接,直接更新状态 console.log('[useEventNotifications DEBUG] Socket已连接,直接更新状态'); logger.info('useEventNotifications', 'Socket already connected, updating state immediately'); setIsConnected(true); // 验证状态更新 setTimeout(() => { console.log('[useEventNotifications DEBUG] 1秒后验证状态更新 - isConnected应该为true'); }, 1000); } else { // 否则建立新连接 console.log('[useEventNotifications DEBUG] Socket未连接,开始连接...'); socketService.connect(); } // 新事件处理函数 - 使用 ref 中的回调 const handleNewEvent = (eventData) => { console.log('\n[useEventNotifications DEBUG] ========== Hook 收到新事件 =========='); console.log('[useEventNotifications DEBUG] 事件数据:', eventData); console.log('[useEventNotifications DEBUG] 事件 ID:', eventData?.id); console.log('[useEventNotifications DEBUG] 事件标题:', eventData?.title); console.log('[useEventNotifications DEBUG] 设置 newEvent 状态'); setNewEvent(eventData); console.log('[useEventNotifications DEBUG] ✓ newEvent 状态已更新'); // 调用外部回调(从 ref 中获取最新的回调) if (onNewEventRef.current) { console.log('[useEventNotifications DEBUG] 准备调用外部 onNewEvent 回调'); onNewEventRef.current(eventData); console.log('[useEventNotifications DEBUG] ✓ 外部 onNewEvent 回调已调用'); } else { console.log('[useEventNotifications DEBUG] ⚠️ 没有外部 onNewEvent 回调'); } console.log('[useEventNotifications DEBUG] ========== Hook 事件处理完成 ==========\n'); }; // 订阅事件推送 console.log('\n[useEventNotifications DEBUG] ========== 开始订阅事件 =========='); console.log('[useEventNotifications DEBUG] eventType:', eventType); console.log('[useEventNotifications DEBUG] importance:', importance); console.log('[useEventNotifications DEBUG] enabled:', enabled); socketService.subscribeToEvents({ eventType, importance, onNewEvent: handleNewEvent, onSubscribed: (data) => { console.log('\n[useEventNotifications DEBUG] ========== 订阅成功回调 =========='); console.log('[useEventNotifications DEBUG] 订阅数据:', data); console.log('[useEventNotifications DEBUG] ========== 订阅成功处理完成 ==========\n'); }, }); console.log('[useEventNotifications DEBUG] ========== 订阅请求已发送 ==========\n'); // 保存取消订阅函数 unsubscribeRef.current = () => { socketService.unsubscribeFromEvents({ eventType }); }; // 组件卸载时清理 return () => { console.log('\n[useEventNotifications DEBUG] ========== 清理 WebSocket 订阅 =========='); // 取消订阅 if (unsubscribeRef.current) { console.log('[useEventNotifications DEBUG] 取消订阅...'); unsubscribeRef.current(); } // 移除监听器 console.log('[useEventNotifications DEBUG] 移除事件监听器...'); socketService.off('connect', handleConnect); socketService.off('disconnect', handleDisconnect); socketService.off('connect_error', handleConnectError); // 注意:不断开连接! // socketService 是全局单例,可能被多个组件使用 // 断开连接会影响其他组件,所以只移除监听器和取消订阅 console.log('[useEventNotifications DEBUG] ⚠️ 保持连接(socketService是全局单例)'); // socketService.disconnect(); // 注释掉,不主动断开 console.log('[useEventNotifications DEBUG] ========== 清理完成 ==========\n'); }; }, [eventType, importance, enabled]); // 移除 onNewEvent 依赖 // 监控 isConnected 状态变化(调试用) useEffect(() => { console.log('[useEventNotifications DEBUG] ========== isConnected 状态变化 =========='); console.log('[useEventNotifications DEBUG] isConnected:', isConnected); console.log('[useEventNotifications DEBUG] ==========================================='); }, [isConnected]); console.log('[useEventNotifications DEBUG] Hook返回值 - isConnected:', isConnected); return { newEvent, // 最新收到的事件 isConnected, // WebSocket 连接状态 error, // 错误信息 clearNewEvent: () => setNewEvent(null), // 清除新事件状态 }; }; /** * 简化版 Hook:只订阅所有事件 */ export const useAllEventNotifications = (onNewEvent) => { return useEventNotifications({ eventType: 'all', importance: 'all', onNewEvent, }); }; /** * Hook:订阅重要事件(S 和 A 级) */ export const useImportantEventNotifications = (onNewEvent) => { const [importantEvents, setImportantEvents] = useState([]); const handleEvent = (event) => { // 只处理 S 和 A 级事件 if (event.importance === 'S' || event.importance === 'A') { setImportantEvents(prev => [event, ...prev].slice(0, 10)); // 最多保留 10 个 if (onNewEvent) { onNewEvent(event); } } }; const result = useEventNotifications({ eventType: 'all', importance: 'all', onNewEvent: handleEvent, }); return { ...result, importantEvents, clearImportantEvents: () => setImportantEvents([]), }; }; export default useEventNotifications;