Reputation: 611
I'm using JavaScript and the Union platform How would I go about diagnosing this problem? Many thanks.
Upvotes: 60
Views: 211517
Reputation: 708
In React if you're writing some kind of App's wrapper component and connect to websocket in useEffect like so:
React.useEffect(() => {
const ws = new WebSocket('ws://localhost:8001')
setWS(ws)
return () => {
ws.close()
}
}, [])
this is due to React's strict mode intentional remounting of all components twice to help debug side effects, even if you have empty array of dependencies. See this question on Stackoverflow for more info
<React.StrictMode>
in ReactDOM.createRoot for example in Vite, or by settings reactStrictMode: false
in config for example in Next.js)const [ws, setWS] = React.useState<WebSocket | null>(null)
const wsRef = React.useRef<WebSocket | null>(null)
React.useEffect(() => {
if (!wsRef.current || wsRef.current.readyState === WebSocket.CLOSED) {
const ws = new WebSocket('ws://localhost:8001')
wsRef.current = ws
setWS(ws)
}
return () => {
if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
wsRef.current.close()
}
}
}, [])
Upvotes: 2
Reputation: 846
In React you need to add this to your useEffect
in return
useEffect(() => {
const socket = new WebSocket(address);
return () => {
if (socket.readyState === 1) { // <-- This is important
socket.close();
}
}
}, []);
However it not only the best solution! You need use hooks instead of using socket connection directly in view/component it can prevents multiple creation of socket connection.
Also socket connection should closed by backend if its not in use, whenever frontend is communicating or not.
Upvotes: 18
Reputation: 28532
In React, if you subscribe to websockets in useEffect
, this error is fine when running in Strict Mode. React would create the subscription twice in Strict Mode, and the first 1 is thrown away immediately, be sure to close the first one!
...because it causes a memory leak. You end up with 2 subscriptions in React Strict mode (and local development). Why? It doesn't clean up the first subscription caused when the component renders twice. If the first component hasn't connected yet, you won't close it (socket.readyState === 1
is false). Eventually, the first WebSocket will eventually connect too.
This can also happen in production, when the component is re-rendered faster than the connection is formed. Your client and websocket server take longer to connect (larger distances/latencies), so this can definitely happen.
It hides the browser warning message, but adds a bug instead.
Upvotes: 11
Reputation: 15467
If you go to http://jsbin.com/ekusep/6/edit and view the JavaScript console you'll see the 'WebSocket is closed before the connection is established' logged. I've tested this in Chrome.
In this code what it means is that ws.close()
was called (by user code) before the connection was even given a chance to be established.
So, the cause of this error is if code attempts to close the WebSocket connection before it's had a chance to actually connect.
Upvotes: 31