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

时间:2018-03-09 19:24:11

标签: reactjs typescript redux 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);
}

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

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:2)

您的getCamerasSuccess未被调用,因为当您调用函数时它会被执行但是当您调用生成器函数时它只会返回一个迭代器对象,您必须在该对象上继续调用它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)。

E.g:

...
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));
}