当前位置: 首页 > 科技观察

React中如何正确使用socket.io客户端?_0

时间:2023-03-14 22:10:37 科技观察

最近在一个React项目中,使用了socket.io来处理即时消息。有几个问题很容易被忽略,比如:React单页应用中如何防止出现多个socket实例,以及在任何组件中如何方便的获取socket实例,又不要有多个监听器对于页面切换时的某个事件。在这篇文章中,我将与大家分享我在React中使用Socket.io客户端的一些经验。希望对此有疑惑的朋友能给我一些帮助。也许你会有一些更好的实现方法。欢迎交流!CreatingaSocketContext本文的实现是利用状态管理工具保存socket实例,供子组件使用。如果使用ReactHooks,可以使用它提供的useContextAPI,实现起来也很简单。//contexts/socket.tsximport{createContext,ReactNode,useContext}from'react';从'socket.io-client'导入io,{Socket};constSOCKET_URL='ws://localhost:8080';exportconstsocket=io(SOCKET_URL,{transports:['websocket'],});constSocketContext=createContext(socket);SocketContext.displayName='SocketContext';exportconstSocketProvider=({children}:{孩子:ReactNode})=>({children});exportconstuseSocket=()=>{constcontext=useContext(SocketContext);returncontext;};//contexts/index.tsximport{ReactNode}from'react';import{SocketProvider}from'./Socket';constAppContextProviders=({children}:{children:ReactNode})=>({children});导出默认的AppContextProviders;其中constsocket=io(SOCKET_URL),可能有小伙伴会有疑惑,为什么不执行socket.connect()呢?socket.io客户端默认为对于动态链接,如果autoConnect属性声明为false,则需要手动执行上面的链接。socket会在页面第一次加载时初始化,解决了第一个问题:“React单页面应用实例中如何防止多个socket”。根组件提供套接字。在项目的App.js文件中引入我们自定义的Provider,将AppProviders组件作为根组件放在最顶层,这样所有被包装的组件都可以使用AppProviders组件提供的属性。也解决了第二个问题:“如何方便的获取任意组件中的socket实例”。从'./contexts'导入AppProviders;导入'./App.css';constApp=()=>(...);导出默认应用程序;在任何子组件中使用套接字组件A来侦听来自服务器的消息。useEffect()是React中内置的Hook。如果第二个参数依赖数组为空,则传入的第一个函数在组件中只会执行一次。只要依赖数组的一个状态更新,useEffect()传入的第一个函数也会被执行。另外需要注意的是,useEffect()传入的是第一个函数,它返回的函数是在函数组件卸载的时候调用的。通常,我们使用useEffect()来模拟类组件的componentDidMount和componentWillUnmount行为。当组件被卸载时,使用socket.off()来移除事件监听器。其实这样可以防止内存泄露,也解决了开头提到的第三个问题:“对于某个事件,不要随着页面切换出现过多的监听器”。从“反应”中导入{useEffect};从'../../contexts/Socket'导入{useSocket};constComponentA=()=>{constsocket=useSocket();useEffect(()=>{//componentDidMountsocket.on('message',handleMessage);//监听消息return()=>{//componentWillUnmountsocket.off('message',handleMessage);};},[插座]);返回();};导出默认组件A;组件B,向服务器发送消息。在我们的组件B中,我们也可以使用自定义的useSocketHook来获取初始初始化的socket实例,但是这不会生成新的socket实例。从“反应”中导入{useEffect};从'../../contexts/Socket'导入{useSocket};constComponentB=()=>{constsocket=useSocket();consthandleSendMessage=()=>{socket.emit('compress',data);//发送消息}return

//...发送消息
;};导出默认ComponentB;