fix(websocket): use singleton socket to prevent disconnection on re-render

This commit is contained in:
hailin 2026-01-10 01:26:49 -08:00
parent bd65a431aa
commit 0cd667b5c8
1 changed files with 30 additions and 9 deletions

View File

@ -2,6 +2,10 @@ import { useCallback, useEffect, useRef } from 'react';
import { io, Socket } from 'socket.io-client';
import { useChatStore, Message } from '../stores/chatStore';
// Singleton socket instance to prevent multiple connections
let globalSocket: Socket | null = null;
let currentUserId: string | null = null;
export function useChat() {
const socketRef = useRef<Socket | null>(null);
const {
@ -16,14 +20,32 @@ export function useChat() {
setConnected,
} = useChatStore();
// Initialize WebSocket connection
// Initialize WebSocket connection (singleton pattern)
useEffect(() => {
if (!userId) return;
// If socket exists for same user, reuse it
if (globalSocket && currentUserId === userId && globalSocket.connected) {
socketRef.current = globalSocket;
setConnected(true);
return;
}
// If socket exists for different user or disconnected, clean up
if (globalSocket) {
globalSocket.disconnect();
globalSocket = null;
}
currentUserId = userId;
const socket = io('/ws/conversation', {
path: '/ws/conversation/socket.io',
query: { userId },
transports: ['websocket'],
reconnection: true,
reconnectionAttempts: 5,
reconnectionDelay: 1000,
});
socket.on('connect', () => {
@ -77,7 +99,6 @@ export function useChat() {
socket.on('tool_result', (data) => {
console.log('Tool result:', data);
// Could update message with tool result
});
socket.on('error', (error) => {
@ -85,11 +106,10 @@ export function useChat() {
setStreaming(false);
});
globalSocket = socket;
socketRef.current = socket;
return () => {
socket.disconnect();
};
// Don't disconnect on cleanup - keep singleton alive
}, [userId]);
// Send message
@ -114,15 +134,16 @@ export function useChat() {
};
addMessage(conversationId, userMessage);
// Send via WebSocket
if (socketRef.current?.connected) {
// Send via WebSocket (use globalSocket for reliability)
const socket = globalSocket || socketRef.current;
if (socket?.connected) {
console.log('Sending message via WebSocket:', { conversationId, content: content.trim() });
socketRef.current.emit('message', {
socket.emit('message', {
conversationId,
content: content.trim(),
});
} else {
console.error('WebSocket not connected, cannot send message');
console.error('WebSocket not connected, cannot send message. Socket state:', socket?.connected);
}
},
[userId, currentConversationId, addMessage],