在 redux-saga 中使用回调时出现问题

Issue when using callbacks in redux-saga

我有一个函数(名为 onGetCameras)接受回调函数(例如 getCamerasSuccess);目的是调用 onGetCameras(这是一个外部函数),它执行 AJAX 调用,完成后调用 getCamerasSuccess,传递它收到的结果。

我的是这样的:

// My 'actionCreators' variable is a reference to create my actions
function* getCamerasSaga(action: action.GetCameras) {
  const { onGetCameras } = action;

  const getCamerasSuccess = function*(response: GetCamerasResponse) {
    console.log('SUCCESS', response);
    yield put(actionCreators.getCamerasSuccess(response);
  }

  yield put(actionCreators.getCamerasStart());

  yield call(onGetCameras, getCamerasSuccss);
}

export function* watchCamera() {
  yield takeEvery(ActionTypes.GetCameras, getCamerasSaga);
}

我不明白为什么它没有进入我的 getCamerasSuccess 函数:我从未在该函数中看到我的 console.log 消息

但是,如果我将成功回调更改为普通函数,例如:

const getCamerasSuccess = (response: GetCamerasResponse) => {
  console.log('RESPONSE', response);
}

我可以看到我正在收到我的回复,但是,正如我提到的,使用生成器函数,它似乎永远不会进入该函数内部。

非常感谢任何帮助。

你的 getCamerasSuccess 没有被调用,因为当你调用一个函数时它会被执行但是当你调用一个生成器函数时它只是 returns 你必须继续调用的迭代器对象 next 让它执行。

您的代码仍然无法运行,因为您正试图在不受 redux-saga 控制的生成器中使用 saga 效果。如果您想继续使用回调,您可能会对 cps 效果感兴趣 ( https://redux-saga.js.org/docs/api/#cpsfn-args )。回调必须采用 node.js 样式(第一个参数错误,第二个结果)。

您的代码可能如下所示:

function* getCamerasSaga(action: action.GetCameras) {
  const { onGetCameras } = action;

  yield put(actionCreators.getCamerasStart());
  try {
    const response: GetCamerasResponse = yield cps(onGetCameras);
    console.log('SUCCESS', response);
    yield put(actionCreators.getCamerasSuccess(response));
  } catch(err) { /* ... */ }
}

如果修改 onGetCameras API 不是一个选项,您将不得不使用普通函数作为回调,然后使用 store.dispatch 而不是 put 或者您可以使用 eventChannel (https://redux-saga.js.org/docs/advanced/Channels.html).

创建一些小的效用函数

例如:

...
import { eventChannel, END } from 'redux-saga';

function createCbChannel(fn) {
  return eventChannel(emitter => {
    fn((response) => {
      emitter(response);
      emitter(END);
    });
    return () => emitter(END);
  });
}

function* getCamerasSaga(action: action.GetCameras) {
  const { onGetCameras } = action;

  yield put(actionCreators.getCamerasStart());

  const cbChannel = yield call(createCbChannel, onGetCameras);
  const response: GetCamerasResponse = yield take(cbChannel);
  console.log('SUCCESS', response);
  yield put(actionCreators.getCamerasSuccess(response));
}