refactor: introduce pause method to socket service to preserve event listeners during idle disconnects

This commit is contained in:
pradeepkumar
2026-04-08 22:04:20 +05:30
parent 308bbf90fd
commit 65787bc34c
2 changed files with 35 additions and 10 deletions

View File

@@ -44,7 +44,11 @@ export function PresenceProvider({ children }: { children: React.ReactNode }) {
const disconnectForIdle = useCallback(() => {
if (!isConnectedRef.current) return;
isIdleRef.current = true;
socketService.disconnect();
// Use pause() instead of disconnect() so subscriber handlers
// (useMessaging listeners) survive the reconnect. Otherwise the
// user would have to refresh the page after returning from idle
// to see new messages in real time again.
socketService.pause();
}, []);
// Track socket connection state

View File

@@ -176,17 +176,18 @@ class SocketService {
});
}
/**
* Fully disconnect and clear every subscriber handler. Use ONLY on logout
* — this invalidates every registered listener across the app.
*
* For transient disconnects (tab hidden, user idle), use `pause()` instead
* so React-registered listeners survive the reconnect.
*/
disconnect(): void {
if (this.socket) {
this.socket.removeAllListeners();
this.socket.disconnect();
this.socket = null;
}
this.pause();
this.currentToken = null;
this.isConnecting = false;
this.connectPromise = null;
this.listenersAttached = false;
// Clear all handler sets to prevent leaks
// Clear all handler sets — only safe on logout because every subscriber
// must re-register after a fresh login.
this.messageHandlers.clear();
this.typingStartHandlers.clear();
this.typingStopHandlers.clear();
@@ -199,6 +200,26 @@ class SocketService {
this.authErrorHandlers.clear();
}
/**
* Tear down the socket without clearing subscriber handler sets.
* Used for idle/visibility disconnects so that when we reconnect,
* the existing React hooks' handlers automatically resume receiving
* events without needing to re-register.
*/
pause(): void {
if (this.socket) {
this.socket.removeAllListeners();
this.socket.disconnect();
this.socket = null;
}
this.isConnecting = false;
this.connectPromise = null;
this.listenersAttached = false;
// Intentionally keep: currentToken, messageHandlers, typingStart/StopHandlers,
// statusHandlers, readHandlers, deliveredHandlers, connectionRequest/ResponseHandlers,
// connectionHandlers, authErrorHandlers
}
isConnected(): boolean {
return this.socket?.connected || false;
}