使用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
相关产品推荐
相关产品推荐

