You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 03:15:09