为了使ws在Next.js上工作,需要完成多项任务。
首先,重要的是要意识到我想让我的ws代码在哪里运行。在Next.js上运行的React代码有两个环境:服务器端(构建页面或使用ssr时)和客户端。
在页面构建期间建立ws连接没有太大的用处,因此我将仅介绍客户端的ws。
全局Websocket类是一个仅适用于浏览器的功能,在服务器上不存在。这就是为什么我们需要防止任何实例化,直到代码在浏览器中运行。一种简单的方法是:
export const isBrowser = typeof window !== "undefined";
export const wsInstance = isBrowser ? new WebSocket(...) : null;
此外,您不必使用React上下文来保存实例,完全可以保持全局范围并导入实例,除非您希望懒惰地打开连接。
如果您仍然决定使用React上下文(或在React树的任何位置初始化ws客户端),则重要的是对实例进行记忆化,以便它不会在React节点的每次更新时创建。
const wsInstance = useMemo(() => isBrowser ? new WebSocket(...) : null, []);
或者
const [wsInstance] = useState(() => isBrowser ? new WebSocket(...) : null);
在React中创建的任何事件处理程序注册都应该包装在一个useEffect
中,并带有一个返回函数,该函数会删除事件侦听器,以防止内存泄漏,同时应指定依赖项数组。如果您的组件已卸载,则useEffect
钩子也将删除事件侦听器。
如果您希望重新初始化ws并且释放当前连接,则可以执行类似以下操作:
const [wsInstance, setWsInstance] = useState(null);
const updateWs = useCallback((url) => {
if(!browser) return setWsInstance(null);
if(wsInstance?.readyState !== 3)
wsInstance.close(...);
const newWs = new WebSocket(url);
setWsInstance(newWs);
}, [wsInstance])
useEffect(() => {
if(isBrowser) {
const ws = new WebSocket(...);
setWsInstance(ws);
}
return () => {
if(ws?.readyState !== 3)
ws.close(...)
}
}, [])
new WebSocket
不起作用?你有错误吗? - DanilauseEffect()
钩子中调用new Websocket()
来在客户端实例化它,或者使用其他方式来延迟 WebSocket 的实例化。 - Calvin