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
相关产品推荐
相关产品推荐

