在 websocket 回调中调用 redux-saga 中的 redux 操作(stomp + sockjs)

hei*_*584 4 stomp websocket reactjs redux redux-saga

我在我的项目中使用reduxredux-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,
        });
      });
      ...
      ....
    }
  );
}
Run Code Online (Sandbox Code Playgroud)

或者也许这个 WebSocket 应该以完全不同的方式实现redux-saga

Nic*_*wer 7

您将无法yield put在回调函数中使用。Stompjs 对 saga 一无所知,所以当给定一个生成器函数时,它不知道它应该做什么。

最简单的方法虽然不一定是最好的,但在回调中直接进入 redux store,并在不涉及 redux-saga 的情况下调度 action。例如:

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,
  });
});
Run Code Online (Sandbox Code Playgroud)

如果您想使用更 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();
  });
}
Run Code Online (Sandbox Code Playgroud)

然后你会像这样使用它:

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,
    });
  }
}
Run Code Online (Sandbox Code Playgroud)