Laravel Echo搭配React接收websocket消息出现重复问题如何解决?
问题原因
- React组件的函数体会在每次组件重渲染时完整执行一次,直接在App组件体内编写
echo.channel().listen()逻辑,每触发一次App组件重渲染就会新增一个重复的WebSocket事件监听器,同一个消息推送会触发所有已注册的监听器执行,自然会收到多条重复消息。 - 如果你使用的是React 18及以上版本,且项目开启了严格模式(
<StrictMode>),开发环境下组件会默认执行两次挂载流程,哪怕App组件没有重渲染,首次加载就会注册两个相同的监听器,第一次推送就会出现两条重复消息。
正确处理方案
符合React规范的做法是把事件监听这类副作用逻辑放到useEffect钩子中执行,同时在清理函数中移除监听器、退出频道,避免内存泄漏和重复监听:
import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { ticketReceived } from './yourSlicePath'; // 替换为实际的slice导入路径 // Echo实例创建逻辑保持不变,放在组件外部,全局仅初始化一次 import Echo from "laravel-echo"; window.Pusher = require("pusher-js"); const options = { broadcaster: "pusher", key: "...", cluster: "...", encrypted: false, wsHost: process.env.REACT_APP_WSHOST, wsPort: 6001, forceTLS: false, disableStats: true, authEndpoint: `http://${process.env.REACT_APP_APIURL}/laravel-websockets/auth`, }; const echo = new Echo(options); function App() { const dispatch = useDispatch(); useEffect(() => { // 注册监听器 const channel = echo.channel("ws-test"); const eventHandler = function (e) { if (e) { let data_o = JSON.parse(e.message).data; console.log("socket received",data_o); dispatch(ticketReceived(data_o)); } }; channel.listen("TestWSEvent", eventHandler); // 清理函数,组件卸载/依赖变更时执行 return () => { // 移除指定事件的对应监听器 channel.stopListening("TestWSEvent", eventHandler); // 不需要保留频道时可直接退出,彻底释放资源 echo.leaveChannel("ws-test"); }; }, [dispatch]); // Redux的dispatch是稳定引用,不会触发不必要的钩子重执行 // 其余组件逻辑 // ... }
上述实现中useEffect仅会在组件挂载时执行一次监听注册,严格模式下开发环境的二次挂载执行前,会先运行第一次挂载对应的清理函数移除旧监听器,最终只会保留一个有效监听器,不会出现重复接收消息的问题,同时组件卸载时的清理逻辑也避免了内存泄漏。
内容的提问来源于stack exchange,提问作者justadev
相关产品推荐
相关产品推荐

