refactor: introduce pause method to socket service to preserve event listeners during idle disconnects
This commit is contained in:
@@ -44,7 +44,11 @@ export function PresenceProvider({ children }: { children: React.ReactNode }) {
|
|||||||
const disconnectForIdle = useCallback(() => {
|
const disconnectForIdle = useCallback(() => {
|
||||||
if (!isConnectedRef.current) return;
|
if (!isConnectedRef.current) return;
|
||||||
isIdleRef.current = true;
|
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
|
// Track socket connection state
|
||||||
|
|||||||
@@ -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 {
|
disconnect(): void {
|
||||||
if (this.socket) {
|
this.pause();
|
||||||
this.socket.removeAllListeners();
|
|
||||||
this.socket.disconnect();
|
|
||||||
this.socket = null;
|
|
||||||
}
|
|
||||||
this.currentToken = null;
|
this.currentToken = null;
|
||||||
this.isConnecting = false;
|
// Clear all handler sets — only safe on logout because every subscriber
|
||||||
this.connectPromise = null;
|
// must re-register after a fresh login.
|
||||||
this.listenersAttached = false;
|
|
||||||
// Clear all handler sets to prevent leaks
|
|
||||||
this.messageHandlers.clear();
|
this.messageHandlers.clear();
|
||||||
this.typingStartHandlers.clear();
|
this.typingStartHandlers.clear();
|
||||||
this.typingStopHandlers.clear();
|
this.typingStopHandlers.clear();
|
||||||
@@ -199,6 +200,26 @@ class SocketService {
|
|||||||
this.authErrorHandlers.clear();
|
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 {
|
isConnected(): boolean {
|
||||||
return this.socket?.connected || false;
|
return this.socket?.connected || false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user