我在项目中使用redux
和redux-saga
。现在使用WebSocket,我在调用套接字响应的回调内调用FETCH_SUCCESS
redux
操作时遇到问题。我也尝试使回调函数成为生成器,但效果不佳。
function* websocketSaga() {
const socket = new SockJS(`${CONFIG.API_URL}/ws`);
const stomp = Stomp.over(socket);
const token = yield select(selectToken);
stomp.connect(
{
Authorization: `Bearer ${token}`,
},
frame => {
stomp.subscribe('/queue/data', message => {
const response = JSON.parse(message.body);
console.log(response); // here is the proper response, it works
put({
type: FETCH_SUCCESS, // here the FETCH_SUCCESS action is not called
payload: response.dataResponse,
});
});
...
....
}
);
}
或者也许应该在redux-saga
中以完全不同的方式实现此WebSocket?
您将无法在回调函数中使用yield put
。 Stompjs对sagas一无所知,因此不知道给定生成器函数时应该做什么。
最简单的方法(虽然不一定是最好的方法,是直接转到回调中的redux存储,并在不涉及redux-saga的情况下调度操作。例如:
import store from 'wherever you setup your store'
// ...
stomp.subscribe('/queue/data', message => {
const response = JSON.parse(message.body);
store.dispatch({
type: FETCH_SUCCESS,
payload: response.dataResponse,
});
});
[如果您想使用更多的redux-saga-y方法,我建议将订阅包装在event channel中。事件通道采用基于回调的api,并将其转换为可以使用redux-saga的效果与之交互的内容,例如take
这里是您创建事件频道的方式:
import { eventChannel } from 'redux-saga';
function createChannel(token) {
return eventChannel(emitter => {
const socket = new SockJS(`${CONFIG.API_URL}/ws`);
const stomp = Stomp.over(socket);
stomp.connect(
{
Authorization: `Bearer ${token}`,
},
frame => {
stomp.subscribe('/queue/data', message => {
const response = JSON.parse(message.body);
emitter(response); // This is the value which will be made available to your saga
});
}
);
// Returning a cleanup function, to be called if the saga completes or is cancelled
return () => stomp.disconnect();
});
}
然后您将像这样使用它:
function* websocketSaga() {
const token = yield select(selectToken);
const channel = createChannel(token);
while (true) {
const response = yield take(channel);
yield put({
type: FETCH_SUCCESS,
payload: response.dataResponse,
});
}
}
使用Promise
可以轻松实现。只需将与回调相关的代码包装在promise中,然后在回调函数中将其resolve
包装即可。之后,使用yield
从Promise中获取数据。我已使用下面的Promise
修改了您的代码。
function* websocketSaga() {
const socket = new SockJS(`${CONFIG.API_URL}/ws`);
const stomp = Stomp.over(socket);
const token = yield select(selectToken);
const p = new Promise((resolve, reject) => {
stomp.connect(
{
Authorization: `Bearer ${token}`,
},
frame => {
stomp.subscribe('/queue/data', message => {
const response = JSON.parse(message.body);
console.log(response); // here is the proper response, it works
resolve(response); // here resolve the promise, or reject if any error
});
...
....
}
);
});
try {
const response = yield p; // here you will get the resolved data
yield put({
type: FETCH_SUCCESS, // here the FETCH_SUCCESS action is not called
payload: response.dataResponse,
});
} catch (ex) {
// handle error here, with rejected value
}
}