Search code examples
javascriptreactjswebsocket

Where to storage a websocket connection?


My question is more about an alternative to store a ws connection. Initially I thought about storing in the session or localStorage, but ws objects are not supported, only primitive data types.

I am wondering what would be the alternatives?

What I am trying to achieve is once I reload the page, I don't lose the ws connection because I have a event sending ws.send(), and after reloading the page it becomes undefined.

Code:

const startConn = () => {
        const ws = new WebSocket('wss://4z2ysa3nod.execute-api.ap-southeast-2.amazonaws.com/Test/'); // TODO: use ENV variable
        setSocket(ws);

        ws.onopen = () => {
            console.log('[onopen] WebSocket connected');
            setStreaming(true);
            console.log("ws", ws);
            ws.send(JSON.stringify({
                action: 'start-streaming-data',
                data: configuration
            }));
        };

        ws.onmessage = (event) => {
            // i am storing data here, removed because not relevant
        })

            setPlotData(prevData => {
                const dataArray = Array.isArray(prevData) ? prevData : [];
                const newData = [
                    ...dataArray,
                    { time: new Date().toLocaleTimeString(), data: data.graph }
                ];
                // Limit the number of data points to preserve interval
                if (newData.length > 10) {
                    newData.shift();
                }
            
                sessionStorage.setItem('plotData', JSON.stringify(newData));
                return newData; // return new array to trigger re-render
            });
        };

        ws.onclose = () => {
            setStreaming(false);
            // clearInterval(intervalId);
            console.log('[onclose] WebSocket disconnected:');
        };

        return () => {
            ws.close();
        };
    }

    useEffect(() => {
        // TODO: simulating receiving data from sensor
        let intervalId;

        if (streaming) {
            intervalId = setInterval(() => {
                if (socket !== null) {
                    socket.send(JSON.stringify({
                        action: 'start-streaming-data',
                        data: configuration
                    }));
                } else {
                    console.log("[wsSend] socket is null");
                }
            }, 1000);
        } else {
            clearInterval(intervalId);
        }

        return () => clearInterval(intervalId);
    }, [streaming, configuration]);

Solution

  • A websocket connection cannot be saved across page reloads by storing it somewhere. Trying to put it in localStorage, sessionStorage or in a database is pointless and doesn't work.

    You could either prevent page reloads from actually happening - the simplest solution.

    Or - allowing page reload - you could keep the connection alive in a place different from your page's environment, e.g. as deceze's comment suggests in a Shared Web Worker.

    Both solutions for keeping the socket connection alive might be overkill though. The most common tactic is to allow the connection to break and just re-establish it after page reload. If you face weird problems/errors on client or server side after implementing this, try gracefully closing the connection.

    Why is your ws variable undefined after reload?

    The page reload wipes the JavaScript environment clean (among other actions like building a new DOM). More precisely, the page's JavaScript Execution Context gets replaced by a brand new one. That's why the old variables, functions, objects, etc. are all gone.

    To learn more about where JavaScript is or can be executed, see the 4-parts Chrome Developer Blog series "Inside look on modern web browser".