You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Socket.io开发聊天应用时客户端重复发送消息问题求助

问题诊断

你的核心问题出在服务器端adduser事件内部嵌套绑定sendMessage监听器的逻辑上:

  • 客户端的useEffect依赖data,每次消息发送后缓存失效、data更新时,会重复触发adduser事件;
  • 每触发一次adduser,服务器就会给当前socket新增一个sendMessage的once监听器。虽然once保证单个监听器只执行一次,但多次绑定后,每次调用sendMessage会触发所有已绑定的监听器,最终导致消息被多次广播。

修复方案

1. 服务器端(app.js)调整

将sendMessage监听器移到connection根层级,不再嵌套在adduser内部,同时让客户端发送消息时携带chatId,确保服务器能精准广播到目标房间:

io.on("connection", (socket) => {
  console.log("Connected", socket.id);

  socket.on("adduser", ({ receiverId, chatId }) => {
    console.log("chatId", chatId);
    console.log("receiverId", receiverId);
    // socket.join支持重复调用,无需判断房间是否存在,避免重复绑定监听器
    socket.join(`${chatId}`);
  });

  // 直接在连接层级监听sendMessage,每个socket仅绑定一次
  socket.on("sendMessage", ({ message, chatId }) => {
    console.log(message, chatId);
    io.sockets.in(`${chatId}`).emit(`${chatId}`, { msg: message, chatId });
  });

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

2. 客户端(adminMessageContent.jsx)调整

  • 修改handleSend,发送消息时带上chatId,让服务器知道要广播到哪个房间;
  • 修正消息监听的useEffect依赖项,避免闭包导致的旧数据问题:
// 修复handleSend,携带chatId
const handleSend = () => {
  const objMsg = { chatId: id, sender: sender, message: msg };
  updateMsg(objMsg);
  socket.emit("sendMessage", {
    message: msg,
    chatId: id // 新增chatId参数
  });
  setMsg("");
};

// 修复消息监听的useEffect依赖项
useEffect(() => {
  const eventHandler = ({ msg, chatId }) => {
    queryClient.invalidateQueries(["message", chatId]);
    console.log(chatId);
    console.log(msg);
  };
  socket.on(`${id}`, eventHandler);
  return () => {
    socket.off(`${id}`, eventHandler);
  };
}, [id, queryClient]); // 新增id和queryClient作为依赖

内容的提问来源于stack exchange,提问作者Riya Bhanvadia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 10:01:33