【问题标题】:Getting duplicate messages with React + Socket.IO chat app使用 React + Socket.IO 聊天应用程序获取重复消息
【发布时间】:2023-01-05 12:57:05
【问题描述】:

尝试创建一个简单的 React 聊天应用程序,但我遇到了出现重复消息的问题。我用node server.js运行服务器,在一个单独的终端用npm start运行客户端,然后在localhost:3000打开两个窗口。我可以发送消息,但我发送的任何消息都会收到 x2。例如(在一个窗口上提交带有“我只发送了一次”的表单后,这是第二个窗口中出现的内容):

我在服务器端执行了 console.log,并且只从服务器接收到一条消息。

这是我的server.js 文件:

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);
  });
});

这是我的socket.js 文件:

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;

这是我的App.js 文件:

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;

【问题讨论】:

  • 我真的不明白为什么,但请尝试删除 useEffects 清理功能上套接字事件的事件侦听器。您可能会以某种方式订阅两次。
  • 也可以试试message以外的名字。 socket-io 可能正在使用该名称进行某些默认行为

标签: reactjs socket.io


【解决方案1】:

正如 punjira 在评论中回答的那样,删除 useEffect 的事件监听器是有效的。

具体来说,之前:

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

后:

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

【讨论】:

    【解决方案2】:

    如果您使用 UseEffects Hooks,您需要clean up

    前 :

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

    您可以添加此行进行清理:

      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
      }, []);
    

    【讨论】: