使用store中全局Socket.IO实例时socket.on事件被重复触发如何解决?
2026-10-20
问题原因 #
- 全局Socket实例是单例对象,生命周期和应用一致,不会随组件卸载/重渲染销毁
-
你将
socket.on('finding', ...)直接写在组件顶层执行,组件每触发一次重渲染,就会给同一个Socket实例新增一个finding事件的匿名监听器,旧的监听器不会自动清除 -
后端触发一次
finding事件时,Socket实例上绑定的所有同事件名监听器都会依次执行,所以打印次数等于累计注册的监听器数量,组件重渲染次数越多打印次数越高 - 组件内创建Socket实例时,每次组件重渲染/卸载都会销毁旧实例、创建新实例,旧实例上绑定的监听器会被回收,所以只会打印一次
解决方案 #
核心逻辑是: 组件绑定的Socket事件监听器,必须在组件卸载时主动清理 ,正确实现方式如下:
-
将事件注册逻辑放到
useEffect中,同时返回清理函数调用socket.off移除对应监听器,注意要给监听器使用命名函数,保证off时能匹配到相同的函数引用:
const socketStore = useContext(SocketStoreContext);
const socket = socketStore.socket;
// 此处替换为你实际获取user对象的逻辑
const user = useUser()
const handleFinding = useCallback(() => {
console.log('called');
}, [])
useEffect(() => {
// 组件挂载时注册监听器
socket.on('finding', handleFinding);
// 组件卸载时清理监听器
return () => {
socket.off('finding', handleFinding);
}, [socket, handleFinding])
const handleFindPartner = () => {