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

在Redux Saga中复用WebSocket连接对象的问题咨询

解决方案

核心思路是将WebSocket实例提升到闭包上层持有,同时通过Redux Saga监听主动发消息的动作来触发发送逻辑,不需要将WebSocket实例暴露到组件层,符合Saga处理副作用的设计规范。

修改后的完整代码

调整initWebsocket逻辑

function initWebsocket(): { channel: EventChannel<any>, send: (data: any) => void } {
  // 将ws实例提升到顶层作用域,重连时自动更新为最新实例
  let ws: WebSocket | null = null;
  let id: string | undefined;
  let intervalId: number;

  const channel = eventChannel((emitter) => {
    const initConnection = () => {
      const connectionUrl: string = "ws://localhost:4000" 
      ws = new WebSocket(connectionUrl);
      
      ws.onopen = () => {
        id && ws?.send(JSON.stringify({ type: "GET_USER_ID", id }));
        // 心跳定时器
        intervalId = window.setInterval(() => {
          ws?.send(JSON.stringify({ type: "PING" }))
        }, 30000)
      };

      // 补全服务端消息监听逻辑,将消息通过emitter抛给Saga
      ws.onmessage = (event) => {
        const data = JSON.parse(event.data);
        emitter({ type: 'WS_RECEIVE_MESSAGE', payload: data });
      }

      ws.onclose = (e) => {
        console.log("4秒后自动重连");
        intervalId && clearInterval(intervalId);
        id && setTimeout(initConnection, 4000); 
      };
    };

    initConnection();

    // 连接关闭时的清理逻辑
    return () => {
      ws?.close();
      intervalId && clearInterval(intervalId);
      console.log("Socket连接已关闭");
    };
  });

  // 暴露统一发送方法,自动判断连接状态
  const send = (data: any) => {
    if (ws && ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify(data));
    } else {
      // 可自行实现消息队列缓存断连期间的消息
      console.warn('WebSocket未连接,消息发送失败');
    }
  }

  return { channel, send };
}

调整wsConnectionWorker监听逻辑

function* wsConnectionWorker() {
  const { channel, send } = yield call(initWebsocket);
  // 同时监听服务端下行消息、前端主动发消息的动作
  while (true) {
    const action: Action<any> = yield take([channel, 'WS_SEND_MESSAGE']);
    if (action.type === 'WS_SEND_MESSAGE') {
      // 触发主动发送逻辑
      send(action.payload);
    } else {
      // 服务端消息同步到Redux store
      yield put(action);
    }
  }
}

组件内使用方式

需要主动发送消息时直接dispatch对应动作即可:

import { useDispatch } from 'react-redux';

function MyComponent() {
  const dispatch = useDispatch();

  const handleSendEvent = () => {
    dispatch({
      type: 'WS_SEND_MESSAGE',
      payload: {
        type: '自定义事件类型',
        data: { /* 要发送的业务数据 */ }
      }
    })
  }

  return <button onClick={handleSendEvent}>发送消息</button>
}

优化建议

  • 可以在initWebsocket中新增消息队列,断连期间发送的消息暂存到队列,连接恢复后批量发送避免消息丢失
  • 可以新增WS_CLOSE_CONNECTION动作监听,用户退出登录时主动关闭WebSocket连接、清理资源

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.13 04:06:01