【问题标题】:Socket.IO is creating 2 socket IDS every time a new user joins a room instead of one每次新用户加入房间而不是一个房间时,Socket.IO 都会创建 2 个套接字 IDS
【发布时间】:2022-10-31 00:55:31
【问题描述】:

我正在创建一个协作反应应用程序,因为每次新用户加入房间时,socket io 都会为每个用户生成 2 个 id,我遵循文档代码,同样,我不确定为什么会这样,下面是服务端代码(server.js)的sn-p。

const cors = require('cors');
const axios = require('axios');
const {Server} = require('socket.io');
const http = require('http');
const ACTIONS = require('../src/Actions');

const app = express();  // Create an instance of express
const server = http.createServer(app)  // Create an instance of http server
const io = new Server(server); // Create an instance of socket.io server


// Storing a client list
const clients = new Map();


// Switching on the server socket to listen for connections
io.on('connection', (socket) => {

   const clientSocketId = socket.id;   
   
   console.log(clientSocketId+' connected');


   socket.on(ACTIONS.JOIN,({roomId,username})=>{
       console.log(roomId,username)
         clients.set(socket.id,{
               roomId,
               username,
               socketId: socket.id,
         })
        socket.join(roomId);
       const clientlist = Array.from(clients.values())
       clientlist.forEach(client=>{
         io.to(client.socketId).emit(ACTIONS.JOINED,{
             clientlist,
               username,
               socketId: socket.id,
         })
       })
   })

   // The server is listening to two events Code Change and Code Sync
   // Code Change is emitted when the user changes the code
   // Code Sync is called when the user joins the room to sync the previously typed code

   socket.on(ACTIONS.CODE_CHANGE, ({ roomId, code }) => {
    socket.in(roomId).emit(ACTIONS.CODE_CHANGE, { code });
  });

socket.on(ACTIONS.SYNC_CODE, ({ socketId, code }) => {
    io.to(socketId).emit(ACTIONS.CODE_CHANGE, { code });
  });


   // Disconnecting the current socket
    socket.on('disconnecting',()=>{
        console.log(clientSocketId+' disconnected')
        // Getting the list of all the present rooms
        const rooms = Object.keys(socket.rooms);
        rooms.forEach(roomId=>{  
          socket.in(roomId).emit(ACTIONS.DISCONNECTED,{
            socketId: socket.id,
            username: clients.get(socket.id).username,
          })
        })
        clients.delete(socket.id);
        socket.leave();
    })
   
})

const PORT = process.env.SERVER_PORT || 5000;

server.listen(PORT,()=>{console.log('Listening on  '+PORT)});

下面是我如何在客户端初始化套接字


export const initSocket = async () => {
   const options =  {
        transports: ['websocket'],
        reconnection: true,
        reconnectionAttempts: 'Infinity',
        forceNew: true,
        reconnectionDelay: 1000,
        reconnectionDelayMax: 5000,
        timeout: 10000,
        autoConnect: true,
        secure: true,
   }
    const socket = io(process.env.REACT_APP_SERVER_URL,options)
    return socket
}

在我的 Dashboard.js 中,我在 UseEffect 中调用了 init 函数

React.useEffect(()=>{
    // As the user joins the room we initialize the client socket which connects to the server
    const init = async () => {

      socketRef.current = await initSocket(); 

      // Handling connection errors
      socketRef.current.on('connect_error',(err)=>handleError(err))
      socketRef.current.on('connect_failed',(err)=>handleError(err))

      const handleError = (err)=>{
        console.log(err)
        toast({
          title: 'Error connecting to the server',
          status: 'error',
          duration: 9000,
          isClosable: true,
        })
        reactNavigater('/')

      }

      socketRef.current.emit(ACTIONS.JOIN,{
        roomId: roomId,
        username: location.state?.username,
      });

      // Listening for joined event when a even user joins
      socketRef.current.on(ACTIONS.JOINED,({clientlist,username,socketId})=>{
        if(username !== location.state?.username){
          toast({
            title: `${username} has joined the room`,
            status: 'success',
            duration: 9000,
            isClosable: true,
          })
        }
        setClientlist(clientlist)
        socketRef.current.emit(ACTIONS.SYNC_CODE, {
          socketId: socketRef.current.id,
          code: codeRef.current,
      });
      })

      // Listening for disconnected event when a even user disconnects
      socketRef.current.on(ACTIONS.DISCONNECTED,({socketId,username})=>{
          toast({
            title: `${username} has disconnected`,
            status: 'warning',
            duration: 9000,
            isClosable: true,
          })
        // Filter the clientlist to remove the disconnected client
        setClientlist(Clientlist.filter(client=>client.socketId !== socketId))
      }
      )

    }
    init()

    // Here we have multiple listeners, so we have to remove them when the component unmounts
    return ()=>{
      if(socketRef.current){
      socketRef.current.disconnect()
      socketRef.current.off(ACTIONS.JOINED)
      socketRef.current.off(ACTIONS.DISCONNECTED)
      }
    }

  },[])

任何帮助,将不胜感激

【问题讨论】:

    标签: node.js reactjs sockets socket.io


    【解决方案1】:

    如果你开启了严格模式,默认情况下,useEffect 会被调用两次(来自 React 18)。并且您的连接被创建了两次。当每个连接生成新的 ID 时,你会得到两个 ID。

    https://stackoverflow.com/a/72238236/8522881

    My React Component is rendering twice because of Strict Mode

    【讨论】:

    • 非常感谢您的回答。问题是由于严格模式,我可以通过禁用严格模式来解决它
    【解决方案2】:

    您可以只用 useRef 包装您的 socket.io 实例,以便在重新渲染之间保持相同的值,例如:

    import React from 'react'
    
    function MyComponent() {
      const socket = useRef(null)
      
      useEffect(() => {
        if(!socket.current) {
          socket.current = io('ws://my-url/');
        }
      }, [])
      
      // now you can use socket.current and ensure you aways will have only one instance
      
      return (
        <p>hello</p>
      )
    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-28
      • 1970-01-01
      • 2014-07-18
      • 1970-01-01
      • 2021-11-12
      • 2017-05-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多