Building a real-time chat app sounds straightforward until React's rendering model meets WebSockets. In Relay, I built what I thought was a solid real-time integration. Everything seemed to work perfectly—until I started switching between conversations.

What I Built

In Relay, I wanted a clean separation of concerns, so I extracted my WebSocket logic into a custom hook called useWebSocket. It takes an onMessage callback so my Chat UI can decide how to handle incoming messages:

// Chat.tsx

const { sendMessage } = useWebSocket((msg) => {