import { useState, useEffect, useRef, useCallback } from "react"; export interface WebSocketHook { socket: WebSocket | null; connected: boolean; message: string | null; sendMessage: (msg: string) => void; } export default function useWebSocket(url: string): WebSocketHook { const [socket, setSocket] = useState(null); const [message, setMessage] = useState(null); const [connected, setConnected] = useState(false); const socketRef = useRef(null); const reconnectAttempts = useRef(0); const reconnectTimeout = useRef(null); const isUnmounted = useRef(false); const connect = useCallback(() => { if (isUnmounted.current) return; console.log("Connecting to WebSocket..."); console.log("WebSocket URL:", url); const ws = new WebSocket(url); setSocket(ws); socketRef.current = ws; ws.onopen = () => { setConnected(true); reconnectAttempts.current = 0; }; ws.onmessage = (event: MessageEvent) => { setMessage(event.data); }; ws.onerror = (error) => { console.error("WebSocket Error:", error); // 在错误发生时主动关闭连接,触发重连 if (ws.readyState === WebSocket.OPEN) { ws.close(); } }; ws.onclose = () => { setConnected(false); // 清理当前的 socket socketRef.current = null; if (!isUnmounted.current) { // 检查是否已经在重连中 if (reconnectTimeout.current) { clearTimeout(reconnectTimeout.current); } // Attempt to reconnect with increased max attempts if (reconnectAttempts.current < 10) { const timeout = Math.min( Math.pow(2, reconnectAttempts.current) * 1000, 30000, ); // 最大30秒 reconnectAttempts.current += 1; console.log( `Attempting to reconnect in ${timeout / 1000} seconds...`, ); reconnectTimeout.current = setTimeout(() => { connect(); }, timeout); } else { console.warn( "Max reconnect attempts reached. Please refresh the page to try again.", ); } } }; }, [url]); useEffect(() => { connect(); return () => { isUnmounted.current = true; if (socketRef.current) { socketRef.current.close(); } if (reconnectTimeout.current) { clearTimeout(reconnectTimeout.current); } }; }, [connect]); // Function to send messages const sendMessage = useCallback((msg: string) => { if (socketRef.current && socketRef.current.readyState === WebSocket.OPEN) { socketRef.current.send(msg); } else { console.warn( "WebSocket is not open. Ready state:", socketRef.current?.readyState, ); } }, []); return { socket, message, sendMessage, connected }; }