Challenge 2: Show a Reconnecting Indicator — Possible Solution ==================================================================== const chat = new ReconnectingSocket(`wss://example.com/chat?token=${myToken}`); const reconnectBanner = document.getElementById("reconnect-banner"); function attachUiHandlers() { chat.socket.addEventListener("open", () => { reconnectBanner.style.display = "none"; // hide once connected chat.send(JSON.stringify({ type: "join", roomName: "lobby" })); }); chat.socket.addEventListener("close", () => { reconnectBanner.style.display = "block"; // show while attempting to reconnect reconnectBanner.textContent = "Reconnecting..."; }); chat.socket.addEventListener("message", (event) => { const data = JSON.parse(event.data); const messageDiv = document.createElement("div"); messageDiv.textContent = `${data.userId}: ${data.text}`; chatWindow.appendChild(messageDiv); }); } // Because ReconnectingSocket creates a NEW WebSocket object on every // retry (Chapter 5), the handlers must be re-attached to each new // socket — the simplest way is calling attachUiHandlers() again every // time ReconnectingSocket creates a fresh instance, e.g. by having // ReconnectingSocket itself call an onSocketCreated callback from its // connect() method: // // chat.onSocketCreated(attachUiHandlers); WHY THIS WORKS -------------- - The banner's visibility is driven directly by the "open" and "close" events on whichever socket is currently active — showing it in "close" and hiding it in "open" means it's visible for exactly the window between a connection dropping and the next one succeeding, which is precisely the reconnection period Chapter 5's backoff loop covers. - This deliberately reuses the SAME "open" handler that already resends the "join" message (from the capstone's own client code) — the banner logic and the room-rejoin logic live side by side in the same handler rather than as two disconnected pieces of reconnect-handling code. - The comment about re-attaching handlers on every new socket instance is a direct callback to Chapter 5's own tip-box gotcha: since ReconnectingSocket creates a brand-new WebSocket object on every retry, event listeners attached to an OLD socket don't automatically carry over to the new one — attachUiHandlers() needs to run again for each fresh socket, exactly the stale-listener trap that chapter warned about. - Showing "Reconnecting..." rather than something vaguer like just disabling the input silently gives the user an honest, specific signal about what's happening — consistent with Chapter 5's broader point that silently failing to send (or silently losing connection) is worse than clear, visible feedback.