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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 22:24:04