Aarush 01
Aarush 01

Reputation: 23

Socket.io sends 2 messages on receiving end

I'm trying to setup socket.io and here is part of my server.js `

const express = require("express");
const app = express();
const http = require("http");
const cors = require("cors");
const { Server } = require("socket.io");
app.use(cors());

const server = http.createServer(app);

const io = new Server(server, {
  cors: {
    origin: "http://localhost:3000",
    methods: ["GET", "POST"],
  },
});

io.on("connection", (socket) => {
  console.log(`User Connected: ${socket.id}`);

  socket.on("join_room", (data) => {
    socket.join(data);
    console.log(`User with ID: ${socket.id} joined room: ${data}`);
  });

  socket.on("send_message", (data) => {
    socket.to(data.room).emit("receive_message", data);
  });

  socket.on("disconnect", () => {
    console.log("User Disconnected", socket.id);
  });
});

server.listen(3001, () => {
  console.log("SERVER RUNNING");
});

`

and my client side Chat.js:

import React, { useEffect, useState } from "react";
import ScrollToBottom from "react-scroll-to-bottom";

function Chat({ socket, username, room }) {
  const [currentMessage, setCurrentMessage] = useState("");
  const [messageList, setMessageList] = useState([]);

  const sendMessage = async () => {
    if (currentMessage !== "") {
      const messageData = {
        room: room,
        author: username,
        message: currentMessage,
        time:
          new Date(Date.now()).getHours() +
          ":" +
          new Date(Date.now()).getMinutes(),
      };

      await socket.emit("send_message", messageData);
      setMessageList((list) => [...list, messageData]);
      setCurrentMessage("");
    }
  };

  useEffect(() => {
    socket.on("receive_message", (data) => {
      setMessageList((list) => [...list, data]);
    });
  }, [socket]);

  return (
    <div className="chat-window">
      <div className="chat-header">
        <p>Live Chat</p>
      </div>
      <div className="chat-body">
        <ScrollToBottom className="message-container">
          {messageList.map((messageContent) => {
            return (
              <div
                className="message"
                id={username === messageContent.author ? "you" : "other"}
              >
                <div>
                  <div className="message-content">
                    <p>{messageContent.message}</p>
                  </div>
                  <div className="message-meta">
                    <p id="time">{messageContent.time}</p>
                    <p id="author">{messageContent.author}</p>
                  </div>
                </div>
              </div>
            );
          })}
        </ScrollToBottom>
      </div>
      <div className="chat-footer">
        <input
          type="text"
          value={currentMessage}
          placeholder="Hey..."
          onChange={(event) => {
            setCurrentMessage(event.target.value);
          }}
          onKeyPress={(event) => {
            event.key === "Enter" && sendMessage();
          }}
        />
        <button onClick={sendMessage}>&#9658;</button>
      </div>
    </div>
  );
}

export default Chat;

I have two problems with SocketIO Chat. It seems that chat works fine but It sends twice(or more) chats. If User1 sends a message it shows like that. When I entered something it shows what I typed.

And another problem is from User2. If User 2 Typed type something, it returned twice. And I tested User3 and it returned a third time. I don't know why it works like this. enter image description here

and when I am sending some messages it shows double the times on receiving end. What I'm doing wrong?

Upvotes: 0

Views: 1498

Answers (1)

Ahmed Mohamed
Ahmed Mohamed

Reputation: 936

The most likely reason why socket.io sends 2 messages on receiving end in your chat application is that you have registered the same event listener twice. This can happen if you call the socket.on method inside another event handler or a loop, or if you forget to remove the previous listener before adding a new one.

Explanation

Socket.io is a library that enables real-time, bidirectional and event-based communication between the browser and the server. It uses a socket object to represent a connection between a client and a server. The socket object can emit and listen to events, which are messages that carry data.

To listen to an event, you need to use the socket.on method, which takes two arguments: the name of the event and a callback function that will be executed when the event occurs. For example, to listen to the message event, you can write:

socket.on('message', function(data) {
  # do something with data
})

However, if you call the socket.on method more than once with the same event name and callback function, you will register multiple listeners for the same event. This means that every time the event occurs, the callback function will be executed multiple times, resulting in duplicate messages.

To avoid this, you need to make sure that you only register one listener per event per socket. You can do this by:

  • Calling the socket.on method only once, outside of any other event handlers or loops
  • Using the socket.once method instead of the socket.on method, which will register a listener that will be executed only once and then removed
  • Using the socket.off method to remove a listener before adding a new one, which takes the same arguments as the socket.on method

Example

Suppose you have the following code in your server-side script:

io.on('connection', function(socket) {
  socket.on('message', function(data) {
    // do something with data
    socket.emit('message', data) # send the message back to the client
  })
})

And the following code in your client-side script:

var socket = io() # create a socket object
socket.on('message', function(data) {
  // display the message on the chat window
  var chat = document.getElementById('chat')
  var message = document.createElement('p')
  message.textContent = data
  chat.appendChild(message)
})

This code will work fine, as long as the client sends only one message at a time. However, if the client sends multiple messages in a row, the server will emit the message event multiple times, and the client will register multiple listeners for the same event. This will result in the chat window displaying the same message twice for each message sent by the client.

To fix this, you can either use the socket.once method on the client-side, or the socket.off method on the server-side. For example, you can modify the client-side code as follows:

var socket = io() # create a socket object
socket.once('message', function(data) { # use socket.once instead of socket.on
  // display the message on the chat window
  var chat = document.getElementById('chat')
  var message = document.createElement('p')
  message.textContent = data
  chat.appendChild(message)
  socket.on('message', arguments.callee) # re-register the listener for the next message
})

Or, you can modify the server-side code as follows:

io.on('connection', function(socket) {
  socket.on('message', function(data) {
    // do something with data
    socket.off('message', arguments.callee) # remove the listener before emitting the event
    socket.emit('message', data) # send the message back to the client
    socket.on('message', arguments.callee) # re-register the listener for the next message
  })
})

Either way, this will ensure that the client and the server only have one listener per event per socket, and that the chat window only displays one message per message sent by the client."""

Upvotes: 3

Related Questions