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

问题描述 投票:1回答:2

我在项目中使用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,
        });
      });
      ...
      ....
    }
  );
}

或者也许应该在redux-saga中以完全不同的方式实现此WebSocket?

reactjs redux websocket redux-saga stomp
2个回答
1
投票

您将无法在回调函数中使用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,
    });
  }
}

0
投票

使用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
  }

}
© www.soinside.com 2019 - 2024. All rights reserved.