Home > Net >  Socket.IO is creating 2 socket IDS every time a new user joins a room instead of one
Socket.IO is creating 2 socket IDS every time a new user joins a room instead of one

Time:07-07

I am creating a collaborative react app, in that every time a new user is joining the room the socket io is generating 2 id's for every user, I have followed the documentation code, in the same way, I am not sure why is this happening, below is the snippet of the server-side code (server.js).

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)});

And below is how I have initialized the socket on the client-side


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
}

And in my Dashboard.js I have called the init function in UseEffect

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)
      }
    }

  },[])

Any help would be appreciated

CodePudding user response:

If you have strict mode on, what's by default, then useEffect is called twice (from React 18). And your connection is created twice. And as every connection generates new Id, you get two id's.

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

My React Component is rendering twice because of Strict Mode

  • Related