Reconnection
When a connection drops unexpectedly, the manager automatically attempts to reconnect. Subscriptions are restored, in-flight messages are cleaned up, and your app stays in sync.
How It Works
On an unexpected close (any code other than 1000), the manager:
- Drops any in-flight messages and notifies
useSocketInFlightDroplisteners - Clears any pending subscriptions
- Sets the state to
"reconnecting" - Waits using exponential backoff with jitter
- Opens a new connection
- Re-sends all active subscriptions
- Fires
onReadywith the list of restored subscription keys
If disconnect() was called, or the server
closed with code 1000 (normal close), no reconnection is attempted.
Exponential Backoff
Each retry waits longer than the last, with a random 0–1000ms jitter to prevent all clients from reconnecting at the same instant:
delay = min(baseDelay * 2^attempt + random(0, 1000ms), maxDelay)With the default settings (base 1s, cap 30s, 10 attempts):
- Attempt 1: ~1–2s
- Attempt 2: ~2–3s
- Attempt 3: ~4–5s
- Attempt 4: ~8–9s
- Attempt 5: ~16–17s
- Attempts 6–10: 30s (capped)
Total worst-case time before giving up: ~3 minutes. Pass
reconnectMaxAttempts: Number.POSITIVE_INFINITY
to retry forever (useful for long-lived apps that prefer to surface
a stale-connection banner instead of a terminal
"disconnected" state).
Configuration
const manager = new WebSocketManager<TClientMsg, TServerMsg>({
// ...
// Maximum number of reconnect attempts (default: 10)
reconnectMaxAttempts: 10,
// Initial delay before the first retry (default: 1000ms)
reconnectBaseDelayMs: 1_000,
// Maximum delay between retries (default: 30000ms)
reconnectMaxDelayMs: 30_000,
});Online / Offline Detection
The manager listens to the browser's
online and
offline events:
- Offline — the connection is immediately closed and the state moves to "reconnecting"
- Online — the reconnect attempt counter resets to zero and a fresh attempt is scheduled at the base delay (~1–2s)
Force Reconnect
Sometimes you need to tear everything down and start fresh — for example after a token refresh or when switching authenticated contexts:
manager.forceReconnect();
This drops all in-flight messages, clears pending subscriptions, closes
the current connection, resets the attempt counter to zero, and immediately
reopens the socket. The state goes
connected → connecting in a single transition —
there is no transient "disconnected" frame for
subscribers to flicker on.
Subscription Restoration
After reconnecting, the manager re-sends every active subscription
using the subscribe payload from the
first subscriber for that key (first-payload wins — see
Subscriptions).
Your components don't need to track or re-trigger anything. Restored
keys are sent back-to-back; if your app holds many subscriptions per
user, prefer a server-side multi-subscribe envelope or stagger the
restore yourself in onReady.
The onReady callback fires after all
subscriptions have been re-sent. Use it to fetch any data you may have missed
while disconnected:
const manager = new WebSocketManager<TClientMsg, TServerMsg>({
// ...
onReady() {
// Connection is open and subscriptions are restored.
// Good place to sync any missed state.
console.log("Reconnected and ready");
},
});Connection States
Track the connection state in your UI with the
useSocketConnectionState hook:
import { useSocketConnectionState } from "@luciodale/react-socket";
function ConnectionStatus() {
const state = useSocketConnectionState(manager);
const labels = {
idle: "Not connected",
disconnected: "Offline",
connecting: "Connecting...",
connected: "Connected",
reconnecting: "Reconnecting...",
} as const;
return <span>{labels[state]}</span>;
}Next Steps
- Subscriptions — how ref-counting works
- Optimistic Updates — handling in-flight messages on disconnect
- Configuration — all reconnection options