How can I prevent websockets from disconnecting and connecting again when I switch a page in NextJS 13 beta(app folder). Will even pay for the solution, telegram: @itszhu
I switch pages using next/link, pages don’t seem to refresh with this option neither.
My app/dashboard/page.js is a server component.
I’m wrapping the page.js with:
import LayoutApp from '@/server/LayoutApp';
import DashboardPage from './DashboardPage';
export default function Dashboard() {
return (
<>
<LayoutApp render={(session) => <DashboardPage session={session} />} />
</>
);
}
And this is my LayoutApp.js:
import HeaderBE from '@/layout/be/HeaderBE';
import { LayoutWithTopbar } from '@/layout/be/LayoutWithTopbar';
import meAuth from '@/server/auth';
import { WrapWebsocket } from '@/hoc/withWebsocket';
export default async function LayoutApp({ render }, req) {
const session = await meAuth(); // server component
return (
<main className="h-full w-full flex">
<WrapWebsocket session={session}>
<HeaderBE session={session} boss={boss} />
<LayoutWithTopbar session={session}>{render(session)}</LayoutWithTopbar>
</WrapWebsocket>
</main>
);
}
And this is my websocket context:
'use client';
import React, {
createContext,
useEffect,
useState,
useCallback,
useRef,
} from 'react';
import useWebSocket, { ReadyState } from 'react-use-websocket';
export const WebSocketContext = createContext(null);
export const WrapWebsocket = ({ children, session }) => {
const url = `ws://api.site.test:${process.env.PORT || 3000}`;
const [isConnected, setIsConnected] = useState(false);
const pingInterval = useRef(null);
const handleOpen = () => {
setIsConnected(true);
console.log('Connected');
};
const handleClose = () => {
setIsConnected(false);
console.log('close ws');
};
const messageHandlers = useRef([]);
const addMessageHandler = (handler) => {
messageHandlers.current.push(handler);
};
const removeMessageHandler = (handler) => {
messageHandlers.current = messageHandlers.current.filter(
(h) => h !== handler
);
};
const handleMessage = useCallback(
(event) => {
console.log('Received message:', event.data); // Add this line
messageHandlers.current.forEach((handler) => handler(event));
},
[messageHandlers]
);
const { sendMessage, lastMessage } = useWebSocket(url, {
onOpen: handleOpen,
onClose: handleClose,
share: true,
retryOnError: true,
shouldReconnect: (closeEvent) => true,
reconnectAttempts: 25,
reconnectInterval: 15000,
});
const startPingInterval = () => {
return setInterval(() => {
sendMessage(JSON.stringify({ type: 'ping' }));
}, 30000); // Send ping every 30 seconds
};
useEffect(() => {
if (isConnected) {
try {
const credentials = {
wsId: session.user.sessionId,
};
sendMessage(JSON.stringify(credentials));
} catch (error) {
console.log(error);
}
pingInterval.current = startPingInterval();
return () => {
clearInterval(pingInterval.current);
};
}
}, [isConnected, sendMessage]);
useEffect(() => {
if (lastMessage) {
handleMessage(lastMessage);
}
}, [lastMessage, handleMessage]);
useEffect(() => {
const handleVisibilityChange = () => {
if (isConnected) {
clearInterval(pingInterval.current);
pingInterval.current = startPingInterval();
}
}; //document.visibilityState === 'visible' &&
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
};
}, [isConnected, pingInterval]);
return (
<WebSocketContext.Provider
value={{ isConnected, addMessageHandler, removeMessageHandler }}
>
{children}
</WebSocketContext.Provider>
);
};
I tried putting WrapWebsocket around the main layout file which crashed the app.
I tried putting it around the layout file that wraps the app folder, which also didn’t work and it kept reconnecting everytime I switched pages.