我正在尝试使用 redux-saga 从我的 react App 连接到 websocket 服务器,并希望捕获连接丢失(服务器错误,重新启动)以便以 4 秒的间隔重新连接,直到连接再次恢复。问题是在重新连接到 webSocket 时 redux store 不再更新。
我尝试按照以下代码使用 redux-saga 的 eventChannel。不幸的是,没有或者至少我找不到任何文档来回答 ws reconnect in redux-saga。
import {eventChannel} from 'redux-saga';
import {all, takeEvery, put, call, take, fork} from 'redux-saga/effects'
import {INITIALIZE_WS_CHANNEL} from "../../constants/ActionTypes"
import {updateMarketData} from "../actions"
function createEventChannel() {
return eventChannel(emit => {
//Subscribe to websocket
const ws = new WebSocket('ws://localhost:9000/rates');
ws.onopen = () => {
console.log("Opening Websocket");
};
ws.onerror = error => {
console.log("ERROR: ", error);
};
ws.onmessage = e => {
return emit({data: JSON.parse(e.data)})
};
ws.onclose = e => {
if (e.code === 1005) {
console.log("WebSocket: closed");
} else {
console.log('Socket is closed Unexpectedly. Reconnect will be attempted in 4 second.', e.reason);
setTimeout(() => {
createEventChannel();
}, 4000);
}
};
return () => {
console.log("Closing Websocket");
ws.close();
};
});
}
function * initializeWebSocketsChannel() {
const channel = yield call(createEventChannel);
while (true) {
const {data} = yield take(channel);
yield put(updateMarketData(data));
}
}
export function * initWebSocket() {
yield takeEvery(INITIALIZE_WS_CHANNEL, initializeWebSocketsChannel);
}
export default function* rootSaga() {
yield all ([
fork(initWebSocket)
]);
}
更新
为了完成@azundo 为寻找 websocket 和 redux-saga 完整示例的人所接受的答案,我添加了以下代码:
function * initializeWebSocketsChannel() {
console.log("going to connect to WS")
const channel = yield call(createEventChannel);
while (true) {
const {data} = yield take(channel);
yield put(updateMarketData(data));
}
}
export function * startStopChannel() {
while (true) {
yield take(START_CHANNEL);
yield race({
task: call(initializeWebSocketsChannel),
cancel: take(STOP_CHANNEL),
});
//if cancel wins the race we can close socket
ws.close();
}
}
export default function* rootSaga() {
yield all ([
startStopChannel()
]);
}
START_CHANNEL 和 STOP_CHANNEL 操作可以在 componentDidMount 和 componentWillUnmount 分别是 React 组件生命周期。
最佳答案
这不起作用的原因是因为您对 createEventChannel
的递归调用没有被 yield
ed 到 saga 中间件 redux-saga
无法知道后续事件 channel 的创建。您会希望在事件 channel 中定义递归函数,请参阅下面的代码,因此只有一个 eventChannel
始终挂接到商店中。
另请注意,在预期的套接字关闭时添加了发射 END,这样您就不会在不重新连接时让 eventChannel 永远打开。
import {eventChannel, END} from 'redux-saga';
let ws; //define it here so it's available in return function
function createEventChannel() {
return eventChannel(emit => {
function createWs() {
//Subscribe to websocket
ws = new WebSocket('ws://localhost:9000/rates');
ws.onopen = () => {
console.log("Opening Websocket");
};
ws.onerror = error => {
console.log("ERROR: ", error);
};
ws.onmessage = e => {
return emit({data: JSON.parse(e.data)})
};
ws.onclose = e => {
if (e.code === 1005) {
console.log("WebSocket: closed");
// you probably want to end the channel in this case
emit(END);
} else {
console.log('Socket is closed Unexpectedly. Reconnect will be attempted in 4 second.', e.reason);
setTimeout(() => {
createWs();
}, 4000);
}
};
}
createWs();
return () => {
console.log("Closing Websocket");
ws.close();
};
});
}
关于reactjs - 在 redux-Saga 中重新连接到 webSocket 服务器的标准方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58026629/