reactjs - 在 Next.js 中使用 WebSocket

标签 reactjs websocket next.js

我想知道使用 Next.js 页面连接到我的 WebSockets 服务器的最佳方法是什么?我希望用户可以通过一个连接浏览页面,当他关闭页面时,他也会关闭 WebSockets 连接。我尝试使用 React 的 Context API:

const WSContext = createContext(null);

const Wrapper = ({ children }) => {
  const instance = WebSocket("ws://localhost:3000/ws");

  return <WSContext.Provider value={instance}>{children}</WSContext.Provider>;
};

export const useWS = () => useContext(WSContext);

export default Wrapper;
它工作得很好,但在创建连接时却不然。基本new WebSocket语法不起作用,所以我必须使用第三方库,例如 react-use-websocket我不喜欢。同样令人不安的是,我无法关闭连接。 Context 根本不知道页面何时关闭,而且库也不提供用于关闭连接的钩子(Hook)。
我想知道在 Next.js 中处理 WebSockets 连接的最佳方法是什么。

最佳答案

为了让 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 hook 也将删除事件监听器。
如果您希望重新初始化 ws 并处理当前连接,则可以执行类似于以下操作:
const [wsInstance, setWsInstance] = useState(null);

// Call when updating the ws connection
const updateWs = useCallback((url) => {
   if(!browser) return setWsInstance(null);
   
   // Close the old connection
   if(wsInstance?.readyState !== 3)
     wsInstance.close(...);

   // Create a new connection
   const newWs = new WebSocket(url);
   setWsInstance(newWs);
}, [wsInstance])


// (Optional) Open a connection on mount
useEffect(() => {
 if(isBrowser) { 
   const ws = new WebSocket(...);
   setWsInstance(ws);
 }

 return () => {
  // Cleanup on unmount if ws wasn't closed already
  if(ws?.readyState !== 3) 
   ws.close(...)
 }
}, [])

关于reactjs - 在 Next.js 中使用 WebSocket,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68263036/

相关文章:

javascript - React-Bootstrap-Table-Next Sort 动态表上的字母数字字符串

reactjs - 我应该使用 Redux store.subscribe() 还是用react-redux <Provider> 包装我的应用程序?

javascript - 在 NextJS/ReactJS 上设置 Google Optimize 防闪烁脚本

reactjs - 使用 next/dynamic 时,为什么 Next.js 的导入行为与 React.js 不同?

node.js - 如何在同一端口但在不同路径上一起使用 socketio 和 ws

javascript - React+Next.js+Firebase :Auth URL changes to username and password after signInWithEmailAndPassword

reactjs - 使用 CRNA 进行社交共享(创建 React Native 应用程序)

reactjs - 在 React 中导入常用组件

Spring WebSockets 运行时监控 STOMP 帧 - 解释

python - cv2.imdecode()从base64中的图像(通过Websocket收到的mimetype image/jpeg)返回None