Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting duplicate messages with React + Socket.IO chat app

Attempting to create a simple React chat app, but I'm running into an issue where duplicate messages appear. I run the server with node server.js, in a separate terminal run the client with npm start, then open two windows at localhost:3000. I can send a message, but any message I send is received x2. For example (after submitting the form with "i only sent this once" on one window, this is what appears in the second window).:

enter image description here

I did console.log on the server-side, and only one message is being received from the server.

Here is my server.js file:

const express = require("express");
const socketio = require("socket.io");
const http = require("http");
const cors = require("cors");

const PORT = process.env.PORT || 5001;

const app = express();
const server = http.createServer(app);
const io = socketio(server);

app.use(cors());

server.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

io.on("connection", (socket) => {
  socket.on("connection", () => {});
  socket.on("send-message", (message) => {
    console.log(message);
    socket.broadcast.emit("message", message);
  });
});

Here's my socket.js file:

import io from "socket.io-client";

const SERVER = "http://127.0.0.1:5001";

const connectionOptions = {
  forceNew: true,
  reconnectionAttempts: "Infinity",
  timeout: 10000,
  transports: ["websocket"],
};

let socket = io.connect(SERVER, connectionOptions);

export default socket;

Here's my App.js file:

import { useState, useEffect } from "react";
import "./App.css";

import socket from "./socket";

const ChatWindow = () => {
  const [message, setMessage] = useState("");
  const [messages, setMessages] = useState([]);

  const handleMessageChange = (event) => {
    setMessage(event.target.value);
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    socket.emit("send-message", { message: message });
  };

  useEffect(() => {
    socket.on("connection", null);
    socket.on("message", (payload) => {
      setMessages((prev) => {
        return [...prev, payload.message];
      });
    });
  }, []);

  return (
    <div>
      {messages.map((message) => {
        return <h3>message: {message}</h3>;
      })}
      <form onSubmit={handleSubmit}>
        <input value={message} onChange={handleMessageChange}></input>
        <button type="submit">Send Message</button>
      </form>

      <h1>Chat Window</h1>
    </div>
  );
};

function App() {
  return (
    <div className="App">
      <ChatWindow />
    </div>
  );
}

export default App;
like image 405
Brandon Macer Avatar asked Sep 23 '26 12:09

Brandon Macer


1 Answers

If you are using UseEffects Hooks you need to clean up

Before :

  useEffect(() => {
    socket.on("connection", null);
    socket.on("message", (payload) => {
      setMessages((prev) => {
        return [...prev, payload.message];
      });
    });
  }, []);

You can add this line to clean up :

  useEffect(() => {
    socket.on("connection", null);
    socket.on("message", (payload) => {
      setMessages((prev) => {
        return [...prev, payload.message];
      });
    });

    return () => socket.off("message"); // add this line to your code
  }, []);
like image 77
Yoga Meleniawan P Avatar answered Sep 25 '26 07:09

Yoga Meleniawan P



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!