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

React中使用WebSocket发数据时旧setInterval无法清除如何解决

问题根因
  • 闭包陷阱:你的useEffect依赖是空数组,仅在组件首次挂载时执行一次,回调内部捕获的weatherData永远是首次渲染时的初始值,后续weatherData更新后无法被这个旧闭包访问到。
  • 变量作用域冲突:你在ws.open的回调内部重新用const interval声明了同名变量,外层作用域的interval变量始终是undefined,导致useEffect返回的清理函数执行clearInterval(interval)时实际没有清掉任何有效定时器,旧定时器会一直运行发送初始数据。
  • 资源泄漏问题:原代码没有主动关闭WebSocket连接,后续如果useEffect重新执行会新建多个WS连接,每个连接绑定的定时器都会独立运行,就会出现同时发送新旧多份数据的情况。
修复方案

直接调整useEffect逻辑,补全依赖、修正变量作用域、完善清理逻辑即可:

// 把weatherData加入依赖数组,数据变更时重新执行effect
useEffect(() => {
  const ws = new WebSocket("ws://localhost:5000/websockets/weatherStation");
  let interval = null;

  ws.addEventListener('open', () => {
    console.log("We are connected");
    // 不要重新声明interval,直接给外层变量赋值
    interval = setInterval(function () {
      ws.send(JSON.stringify(weatherData));
    }, 2000);
  })

  // 清理函数:先清定时器,再关WS连接
  return () => {
    if (interval) clearInterval(interval);
    if (ws.readyState === WebSocket.OPEN) {
      ws.close();
    }
  };
}, [weatherData])
可选优化(避免频繁重建WS连接)

如果weatherData更新频率很高,不想每次都重连WS,可以用useRef保存最新的weatherData,避免把weatherData加入effect依赖:

// 先声明ref存储最新的weatherData
const weatherDataRef = useRef(weatherData);
// 单独用effect同步weatherData到ref
useEffect(() => {
  weatherDataRef.current = weatherData;
}, [weatherData]);

// WS相关的effect不用依赖weatherData
useEffect(() => {
  const ws = new WebSocket("ws://localhost:5000/websockets/weatherStation");
  let interval = null;

  ws.addEventListener('open', () => {
    interval = setInterval(() => {
      // 发送时从ref取最新值
      ws.send(JSON.stringify(weatherDataRef.current));
    }, 2000);
  })

  return () => {
    if (interval) clearInterval(interval);
    if (ws.readyState === WebSocket.OPEN) {
      ws.close();
    }
  };
}, [])

内容的提问来源于stack exchange,提问作者Nikolay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 06:00:03