Socket.io连接异常致通知计数错误:单次请求触发多次更新排查
问题分析与解决方案
核心问题原因
- 客户端重复建立连接:
socket.connect()写在组件顶层,组件每次渲染(比如状态更新、父组件重渲染)都会执行一次,导致多次建立Socket连接,进而多次触发newCandidateRequest事件。 - 管理员端事件监听未正确清理:虽然在useEffect的清理函数里调用了
socket.disconnect(),但未移除newNotification的事件监听,若组件重新挂载,会重复绑定监听函数,导致同一通知触发多次计数更新。 - 服务端广播范围问题:使用
io.emit会给所有在线客户端(包括发起请求的候选人页面客户端)发送通知,若管理员端有多个标签页/连接,也会收到多次通知。
客户端代码修复
将socket.connect()移到useEffect内部,确保仅在组件挂载时执行一次,同时保证连接建立后再发送事件:
const id = localStorage.getItem('voterId'); const [constituencies, setConstituencies] = useState([]); const [parties, setParties] = useState([]); const [newCandidateRequest, setNewCandidateRequest] = useState({ party: '', constituency: '', description: '', }) useEffect(() => { // 仅在组件挂载时建立连接 socket.connect(); // 连接建立后发送事件 socket.emit('newCandidateRequest'); // 清理函数:断开连接 return () => { console.log('Disconnecting the socket io'); socket.disconnect(); }; }, []) // 空依赖数组,仅执行一次
服务端代码优化
如果不需要给发起请求的客户端发通知,改用socket.broadcast.emit只给其他客户端发送,避免不必要的重复通知:
io.on("connection", (socket) => { console.log("A new client connected."); socket.on("newCandidateRequest", () => { console.log('New candidate request comes'); // 仅向当前socket以外的所有客户端广播通知 socket.broadcast.emit("newNotification"); }); socket.on('disconnect', () => { console.log('A user disconnected'); }); });
管理员端代码修复
确保事件监听在组件卸载时正确移除,避免重复绑定:
const [requests, setRequests] = useState([]); const { notifications, updateNotifications } = useNotify(); useEffect(() => { const handleNewNotification = () => { console.log('Updating the value of notifications'); updateNotifications(); console.log("notifications " + notifications); }; socket.connect(); // 绑定事件监听 socket.on("newNotification", handleNewNotification); // 清理函数:先移除监听再断开连接 return () => { console.log('Turning socket off'); socket.off("newNotification", handleNewNotification); socket.disconnect(); }; }, []) // 空依赖数组,仅执行一次 useEffect(() => { console.log('data is here ' + notifications); }, [notifications]);
额外注意事项
- 确保全局Socket实例是单例的,避免组件每次创建新的Socket实例。
- 若使用React Strict Mode,开发环境下组件会被渲染两次,可能导致useEffect执行两次,可在生产环境测试,或添加标识避免重复触发事件。
内容的提问来源于stack exchange,提问作者Nouman Arshad
相关产品推荐
相关产品推荐

