在条件渲染中卸载组件时,useEffect的清理函数不会执行

前端开发 2026-07-09

我正在构建一个聊天组件,在挂载时会订阅一个 WebSocket,并应在卸载时取消订阅。useEffect中的清理函数在父组件通过条件渲染移除组件时似乎并没有执行。

我想要做的是
<ChatRoom /> 卸载时,取消对 WebSocket 连接的订阅。

function ChatRoom({ roomId }) {
    useEffect(() => {
      const socket = connectToRoom(roomId);
      console.log('subscribed:', roomId);

      return () => {
        console.log('unsubscribed:', roomId);
        socket.disconnect();
      };
    }, [roomId]);

    return <div>Room: {roomId}</div>;
  }

  function App() {
    const [show, setShow] = useState(true);
    return (
      <>
        <button onClick={() => setShow(s => !s)}>toggle</button>
        {show && <ChatRoom roomId="general" />}
      </>
    );
  }

我的预期
当我点击切换按钮时,我期望在控制台看到 已取消订阅:general。

实际发生的情况
在挂载时我只看到一次 已订阅:general。清理日志从未出现,套接字保持打开状态(在网络选项卡中已验证)。

我已经尝试过

  • 确认show实际上已经切换为false(在App中添加了日志)
  • 已移除 <StrictMode>,以排除重复调用的行为
  • 已检查connectToRoom返回的对象中包含 disconnect()

环境

  • React 18.2.0
  • Vite 5.0
  • Chrome 122

解决方案

卸载只有在依赖项为空时才起作用吗?

[roomId] -> only unmount when roomId is changed?
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章