0

I'm facing an issue with my React and Socket.IO application. When a user joins a room, the user's information is getting added twice in the client's array on the client side. The entries have the same username but different socket IDs. Here's a simplified version of my code of server.js and react component

server.js

const express = require('express');
const app = express();
const http = require('http');
const path = require('path');
const { Server } = require('socket.io');
const ACTIONS = require('../src/constants/Actions');

const server = http.createServer(app);
const io = new Server(server);

const userSocketMap = {};

function getAllConnectedClients(roomId) {
    return Array.from(io.sockets.adapter.rooms.get(roomId) || []).map(
        (socketId) => {
            return {
                socketId,
                username: userSocketMap[socketId],
            };
        }
    );
}

io.on('connection', (socket) => {
    console.log('socket connected', socket.id);

    socket.on(ACTIONS.JOIN, ({ roomId, username }) => {
        userSocketMap[socket.id] = username;
        socket.join(roomId);
        const clients = getAllConnectedClients(roomId);
        clients.forEach(({ socketId }) => {
            io.to(socketId).emit(ACTIONS.JOINED, {
                clients,
                username,
                socketId: socket.id,
            });
        });
    });
});

when I console.log the clients it shows console.log('client', clients); two users with the same name and different socket id.

import React, { useEffect, useState, useRef } from "react";
import Client from "../../components/Client";
import Ide from "../../components/Ide";
import { initSocket } from "../../socket";
import ACTIONS from "../../constants/Actions";
import { Navigate, useLocation, useNavigate, useParams } from "react-router";
import { toast } from "react-hot-toast";
import NewChat from "../../components/NewChat";
const EditorPage = () => {
  const socketRef = useRef(null);
  const codeRef = useRef(null);
  const location = useLocation();
  const { roomId } = useParams();
  const [UsernName, setUsernName] = useState("");
  const reactNavigator = useNavigate();
  const [clients, setclients] = useState([]);
  useEffect(() => {
     const init = async () => {
      socketRef.current =  await initSocket();
      socketRef.current.on("connect_error", (err) => handleErrors(err));
      socketRef.current.on("connect_failed", (err) => handleErrors(err));

      function handleErrors(e) {
        console.log("socket error", e);
        toast.error("Socket connection failed , try again later.");
        reactNavigator("/");
      }
      socketRef.current.emit(ACTIONS.JOIN, {
        roomId,
        username: location.state?.username,
      });

      //listening for joined event
      socketRef.current.on(
        ACTIONS.JOINED,
        ({ clients, username, socketId }) => {
          console.log(username);
          console.log(location.state?.username);
          console.log(socketId);
          if (username !== location.state?.username) {
            toast.success(`${username} joined the room`);
            console.log(`${username} joined`);
          }
          if(username===location.state?.username){
            setUsernName(username);
          }
          console.log(clients);

            setclients(clients); // Update the clients state

          socketRef.current.emit(ACTIONS.SYNC_CODE, {
            code: codeRef.current,
            socketId,
          });
        }
      );
   
      // listening for disconnecting
      socketRef.current.on(ACTIONS.DISCONNECTED, ({ socketId, username }) => {
        toast.success(`${username} left the room`);
        setclients((prev) => {
          return prev.filter((client) => client.socketId !== socketId);
        });
      });
    };
    init();
    return () => {
      //cleaning when component unmount
      if (socketRef.current) {
      socketRef.current.off(ACTIONS.JOINED);
      socketRef.current.off(ACTIONS.DISCONNECTED);
      socketRef.current.disconnect();
      }
    };
  }, []);

  if (!location.state) {
    return <Navigate to="/" />;
  }
  return (
    <>
      <div className="mainWrap">
        <div className="edtiroWrap">
          <Ide
            socketRef={socketRef}
            roomId={roomId}
            onCodeChange={(code) => {
              codeRef.current = code;
            }}
            UsernName={UsernName}
          />
        </div>
        <div className="aside">
          <div className="asideInner">
            <h3>Connected</h3>
            <div className="clientList">
              {clients.map((client) => (
                <Client key={client.socketId} username={client.username} />
              ))}
            </div>
          </div>
        </div>
      </div>
      <NewChat socketRef={socketRef} clients={clients} roomId={roomId} />
    </>
  );
};

export default EditorPage;

I am also clearing the socket in return statement, still it is not working

1 Answer 1

1

This could occur because useEffect is called twice when you are in strict mode. Try disabling strict-mode. React Hooks: useEffect() is called twice even if an empty array is used as an argument

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.