Chrissisbeast
Chrissisbeast

Reputation: 51

Socket.io sends back multiple responses only to the sender

so I wanted to dive into Socket.io and I am a complete beginner in it. I am a react developer and decided to test it with react, this is my client side:

import { io } from "socket.io-client";
function App() {
  let [message, setMessage] = useState("");
  let [messages, setMessages] = useState([]);
  const socket = io("http://localhost:4000/", {
    withCredentials: true,
    cors: {
      origin: "http://localhost:4000",
    },
  });

  const sendMessage = (msg) => {
    socket.emit("messageToServer", msg);
  };
  socket.on("messageToClient", (msg) => {
    setMessages((prevMessage) => prevMessage.concat(msg));
  });

  return (
    <div className="App">
      {messages}

      <input
        id="input"
        autoComplete="off"
        onChange={(e) => setMessage(e.target.value)}
      />
      <button onClick={() => sendMessage(message)}>Send</button>
    </div>
  );
}

and this is my server side(Node, Express):

const app = require("express")();
const http = require("http").Server(app);
const io = require("socket.io")(http, {
  cors: {
    origin: "http://localhost:3000",
    methods: ["GET", "POST"],
    credentials: true,
  },
});

io.on("connection", (socket) => {
  let messages = [];
  socket.on("messageToServer", (msg) => {
    io.emit("messageToClient", msg);
    console.log(msg);
  });
});

http.listen(4000, () => {
  console.log("listening on *:3000");
});

So basicly when I write something on the input and click the button, on the node server everything seems fine and the message logs only once, but when I open the tab that I send the message from and for example I typed 'First message' it will print something like: 'First messageFirst messageFirst messageFirst message' and so on... But apparently, the duplication is happening only from the tab I am sending it from, because when I open a new one and test it, on the sender tab I get multiple like i said, but on the new one, I recieve it only one, just like it should be. Thank you in advance!

Upvotes: 0

Views: 724

Answers (1)

Janice Zhong
Janice Zhong

Reputation: 878

The below snippet of code will keep App component being rendered multiple times, thus the same event handler for messageToClient will be registered multiple times and cause unexpected behavior in React.

  socket.on("messageToClient", (msg) => {
    setMessages((prevMessage) => prevMessage.concat(msg));
  });

You should wrap socket on event with useEffect, so that we can make sure nothing is duplicating.

  useEffect(()=>{
    socket.on("messageToClient", (msg) => {
      setMessages((prevMessage) => prevMessage.concat(msg));
    });
    
    // unbind the event handler when the component gets unmounted
    return () => {
      socket.off('messageToClient')
    }
  },[])

Upvotes: 2

Related Questions