如何在socket.io聊天室中实现用户断开连接时的提示消息展示
Socket.io用户断开连接提示失效修复方案
问题根因
- 依赖配置错误:负责注册socket事件的useEffect将
chat加入了依赖数组,每次聊天记录更新都会重新执行该逻辑,导致socket反复重连、事件监听反复注册,第二个useEffect中存储的socket实例很快就会被替换为新实例,触发pre_disconnect时发送的事件无法被正确监听。 - 缺少清理逻辑:注册socket事件的useEffect没有返回清理函数,旧的事件监听和socket连接不会被销毁,会出现大量重复监听、无效连接问题。
- 主动上报方案不可靠:依赖客户端主动发送
pre_disconnect的方案在用户直接关闭页面、网络异常断开时无法触发,提示会失效。
修复代码
服务端(Express/Node)
io.on('connection', socket => { // 存储当前socket对应用户名 let currentUser = '' socket.on('message', ({ name, message }) => { io.emit('message', { name, message }) }) socket.on('join' , (name)=>{ currentUser = name.usnm.toUpperCase() console.log(currentUser, 'joined') socket.broadcast.emit("join" , currentUser + " just joined") }) // 直接监听socket自带的断开事件,不需要客户端主动上报 socket.on('disconnect', () => { if (currentUser) { console.log(currentUser, 'left') socket.broadcast.emit("user_left", currentUser + " just left") } }) })
客户端(React.js)
const socketRef = useRef() // 连接socket + 注册事件逻辑,无需添加chat依赖 useEffect(() => { socketRef.current = io.connect("http://localhost:4000") // 状态更新使用函数式写法,无需依赖外部chat变量 socketRef.current.on("message", ({ name, message }) => { setChat(prev => [ ...prev, { name, message } ]) }) socketRef.current.on("join", (usnm) => { setChat(prev => [ ...prev, {name:usnm} ]) }) socketRef.current.on("user_left", (usnm) => { setChat(prev => [ ...prev, {name:usnm} ]) }) // 组件卸载时清理监听+断开连接 return () => { socketRef.current.offAll() socketRef.current.disconnect() } }, []) // 上报用户加入逻辑 useEffect(() => { let usnm = sessionStorage.getItem("User"); if (socketRef.current && usnm) { socketRef.current.emit("join" ,{usnm}); } }, [])
修复说明
- 使用socket.io自带的
disconnect事件处理断开逻辑,不管是客户端主动断开还是网络异常断开都能触发,可靠性更高。 - 状态更新使用函数式写法,避免将
chat加入useEffect依赖,防止socket反复重连。 - 新增了socket事件和连接的清理逻辑,避免内存泄漏和重复监听问题。
内容的提问来源于stack exchange,提问作者chaos
相关产品推荐
相关产品推荐

