为何update-active-users事件未被清理或重复绑定?
问题
我有一个名为update-active-users的事件监听器,出现了重复监听的情况。确认后端仅触发一次事件,但监听器仍会触发两次。我已在useEffect的清理函数中移除该监听器并断开socket,也曾尝试使用.once方法,但它只能监听一次,无法接收后续触发的事件,不符合需求。需要解决的是:如何让监听器既能正常接收每次触发的事件,又不会出现重复绑定的情况?
相关代码如下:
useEffect(() => { const asyncInit = async () => { // Validate Auth if (token) { // Authenticated flow socket.current = io(`${socketServer}`, { query: { token }, reconnection: true, reconnectionDelay: 1000, timeout: 60000, }); // setIsAuthenticated(true); await getProfile(token); // wait to get profile info //Socket listener function initializeSocket(); socket.current?.on("update-active-users", hndlUpdtActvs); } else { // setIsAuthenticated(false); navigate("/auth"); } }; asyncInit() .catch((err) => { console.log(err); }) .finally(() => {}); return () => { socket.current?.off("update-active-users", hndlUpdtActvs); console.log("Called Disconnect"); socket.current?.disconnect(); socket.current?.on("disconnect", (id) => { console.log(id); // toast({ // title: `User ${id} left the chat`, // duration: 2000, // status: "info", // position: "bottom", // }); }); }; }, []);
解决方案
1. 绑定监听器前先清理旧监听
在调用on绑定新监听器之前,先执行off移除同名事件的已有监听,从根源避免重复绑定:
// 绑定前先清除旧监听 socket.current?.off("update-active-users", hndlUpdtActvs); socket.current?.on("update-active-users", hndlUpdtActvs);
这样即使因组件意外重渲染、socket重连等原因多次执行绑定逻辑,也会先清除旧监听再绑定新的,不会出现重复触发。
2. 排查initializeSocket函数的重复绑定
代码中调用了initializeSocket(),需要确认该函数内部是否也对update-active-users事件做了绑定。如果是,会导致同一事件被绑定两次,需移除该函数内的重复绑定,或者统一监听逻辑。
3. 修正清理函数的socket处理逻辑
当前清理函数中,disconnect后绑定disconnect事件是无效操作,还可能导致socket实例未被彻底清理。调整清理函数如下:
return () => { // 先移除目标事件监听 socket.current?.off("update-active-users", hndlUpdtActvs); // 可选:移除所有监听确保彻底清理 socket.current?.removeAllListeners(); // 断开socket连接 socket.current?.disconnect(); // 清空socket实例引用 socket.current = null; console.log("Socket disconnected and cleaned up"); };
4. 处理socket重连的重复绑定问题
因为开启了reconnection: true,socket重连时会重建连接,需避免此时重复绑定监听。可以通过监听socket的connect事件,在每次连接成功时统一处理监听绑定:
socket.current = io(`${socketServer}`, { query: { token }, reconnection: true, reconnectionDelay: 1000, timeout: 60000, }); // 每次连接成功时,先清理再绑定监听 socket.current.on("connect", () => { socket.current?.off("update-active-users", hndlUpdtActvs); socket.current?.on("update-active-users", hndlUpdtActvs); });
这样无论socket是首次连接还是重连,都能确保监听只绑定一次。
内容的提问来源于stack exchange,提问作者Raman Pratap Singh
相关产品推荐
相关产品推荐

