"Every component that opens its own socket is a small leak waiting to happen. Own the connection once; let the rest just listen."
The stream is app-level, not per-component
Keep has several workspaces that all want live prices — the portfolio view, the market pulse, a focused ticker. The tempting React pattern is for each of those components to open the WebSocket it needs. Keep forbids that. A single app-level hook (useMarketStream) owns the only WebSockets. Every workspace listens to broadcast events (a keep-market-update event) rather than opening its own connection. One owner, many listeners.
Why per-component sockets are a mess
Let each component open its own socket and you sign up for a pile of problems. Now three components hold three connections to the same provider hub, tripling the load. Each has its own mount/unmount lifecycle, so sockets leak when a component unmounts without cleaning up, or reconnect-storm when a view remounts. The components can disagree about the current price because their sockets received ticks at slightly different moments. And 'pause' becomes a nightmare — you have to find and stop every component's socket instead of one. Per-component connections turn one clean concern into N tangled ones.
The bridge and the overlay
Underneath, the flow has a tidy shape. A broadcast tick first updates a thread-safe, process-local price bridge — a small in-memory store of the newest values. Then the REST projections (portfolio, watchlist, focus, pulse, export) overlay that newer value on top of their durable data when they render. So live and durable aren't two competing sources fighting in the UI; live is a thin, fresh layer painted over the stable base at read time. The socket owner keeps the bridge current; everyone else reads the bridge-over-durable composite.