Shared clients
A client is one WebSocket connection that any number of components can use. This page covers the two ways to share one, how the connection's lifetime is managed, and when to pick which.
Two ways to share
By URL
Every useWebSocket(url) call with the same URL (and the same protocols) shares one connection:
The connection's options come from the first component to mount with that URL. Later hooks with the same URL reuse it as-is, and their connection options (json, reconnect, schema, …) are ignored. Their handlers (onMessage, onOpen, …) and enabled still apply. If two parts of your app need different options for the same URL, use a module-level client.
Only mounted components count. A component whose render React throws away, because it suspended or because a transition was interrupted, doesn't open the connection or decide its options. Components that mount together share one connection too, and anything they send from a mount effect reaches it. A component with enabled: false shows the shared connection's status without opening one.
In development, a hook whose connection options differ from the first one's logs a console.warn that names them. Options written inline count as the same when they have the same contents, even though they are new objects and functions on every render. A schema is compared by identity, so create schemas outside components: on React 18, StrictMode's second render can't be told apart from another component, and a schema created during render warns there.
Clients share a connection between the components of one tab. To share one between tabs too, see One connection across tabs.
With a module-level client
createWebSocket defines a connection once, outside any component. Import it wherever you need it:
Creating it doesn't connect. It connects when a hook first uses it.
Three hooks accept a client:
With a client, useWebSocket(chat, handlers) accepts only handlers (onOpen, onMessage, onClose, onError) and enabled. Connection options belong to createWebSocket.
You can also call the client directly from anywhere, including event handlers and non-React code:
Connection lifetime
Clients are reference-counted. You rarely need to open or close them yourself.
- Opens when the first hook using it mounts, or when something reads
client.ready. - Stays open while at least one mounted hook holds it.
- Closes one tick after the last hook unmounts, and its status goes back to
idle. The delay is why StrictMode's mount → unmount → mount and route transitions reuse the socket instead of reconnecting. See StrictMode, Activity and lifecycle.
A hook with enabled: false, or useWebSocket(null), doesn't hold the connection.
When the last hook for a URL releases it, that URL's client is discarded. The next hook for that URL starts a fresh client, so lastMessage starts out undefined again. A module-level client is never discarded and keeps its lastMessage.
Keeping a connection open with connect()
Call client.connect() to keep a connection open even when no component is using it, for example to receive notifications for the whole session:
A connection started with connect() survives every hook unmounting. close() ends it and returns the client to reference counting.
Holding a connection from non-React code
client.acquire() is what the hooks use under the hood. It returns a release function:
The release function is safe to call more than once.
Closing and restarting
client.close(code?, reason?) closes the socket and stops reconnecting, for every component using it. The status becomes closed. Mounted hooks stay mounted but don't reopen it. To start again, call connect() or reconnect(). Once every hook unmounts, the client goes back to idle, and the next hook to mount opens it again. The same goes for a client closed (or one that gave up) while no hook held it: the next hook to mount opens it.
Like WebSocket.close(), close() throws for a code the browser rejects: it takes 1000 or 3000–4999, so 1001 (going away) throws. Nothing changes then, and the connection keeps working.
Which one should I use?
A good rule: start with useWebSocket(url) for a connection used by one component. Once two components share it, or you need it in non-React code, move it to createWebSocket.
See also
createWebSocketand theWebSocketClientinterfaceuseWebSocketEventanduseWebSocketStatus- Performance for high-frequency streams