Ad

Socket IO Emit Events Twice

Situation:

I'm setting up an express server with socket.io and a client using ReactJS. This is my server:

//... another requirement
const socket = require("./socket");

const app = express();
const server = http.createServer(app);
const port = process.env.PORT || 3000;

//... some parsers ...

routes(app);
socket(server);

server.listen(port);
console.log("Server started on: " + port);

And this is my socket:

const socketIO = require("socket.io");

const socket = server => {
  const io = socketIO(server);
  const chat = io.of("/chat");
  chat.on("connection", client => {
    console.log("User started chat!");
    client.on("disconnect", () => {
      console.log("User left chat!");
    });

    client.on("sendMessage", msg => {
      const { id, text } = msg;
      console.log(id + " says: " + text);
      client.broadcast.emit("incomingMessage", {
        //... response data
      });
    });
  });
};

In the client, the Chat Page component will handle sending message to socket and receiving message from socket:

//_ChatBox in Chat Page
const _ChatBox = (/*props*/) => {
  const chat = io("http://localhost" + ":3000/chat");

  chat.on("incomingMessage", message => {
    console.log("Receive message");
    //...handle income message
  });

  const sendMessageToSocket = (data) => {
    chat.emit("sendMessage", data);
  };

  return ( /*JSX*/);
};

Problem:

Everytime a user accesses Chat Page, socket will receive connect event and log User started chat! to console once, but actually, it has logged twice, that means the socket has handled the connect event twice.

And when _ChatBox receives message, it will log Receive message and display that message, but what it has done is log that twice and display the message twice, that also means the socket has emitted the incomeMessage event twice.

What i want: I want the socket only handles those events once.

Ad

Answer

It looks like your component is rendering twice, so calling const chat = io("http://localhost" + ":3000/chat"); twice, giving two connection messages.

You can use a useEffect() hook to only connect on the first render. Passing in an empty array as the second argument means the effect will only be called once:

const _ChatBox = (/*props*/) => {

  useEffect(()=>{
     const chat = io("http://localhost" + ":3000/chat");

    chat.on("incomingMessage", message => {
      console.log("Receive message");
      //...handle income message
     });

     const sendMessageToSocket = (data) => {
      chat.emit("sendMessage", data);
     };
   }, []);


  return ( /*JSX*/);
};
Ad
source: stackoverflow.com
Ad