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

