Проблема при использовании обратных вызовов в redux-saga

1

У меня есть ситуация, когда у меня есть функция (named 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 в мою функцию getCamerasSuccess: я никогда не вижу свое console.log сообщение внутри этой функции

Но, если я изменю свой обратный вызов на успех, чтобы быть нормальной функцией, например:

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

Я вижу, что получаю свой ответ, но, как я уже говорил, используя функцию генератора, кажется, что он никогда не входит внутрь этой функции.

Любая помощь глубоко ценится.

Теги:
redux
redux-saga

1 ответ

2
Лучший ответ

Ваш getCamerasSuccess не вызывается, потому что когда вы вызываете функцию, которую он выполняет, но когда вы вызываете функцию генератора, он возвращает только объект-итератор, по которому вы должны продолжать звонить next чтобы он выполнялся.

Ваш код все равно не будет работать, потому что вы пытаетесь использовать эффект саги в генераторе, который не находится под контролем сокращения-саги. Если вы хотите продолжать работать с обратными вызовами, вам может быть интересен эффект cps (https://redux-saga.js.org/docs/api/#cpsfn-args). Обратный вызов должен быть в стиле node.js, хотя (первый параметр err, второй результат).

Тогда ваш код может выглядеть следующим образом:

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) { /* ... */ }
}

Если модификация API onGetCameras не является вариантом, вам придется либо использовать обычную функцию в качестве обратного вызова, а затем использовать 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));
}
  • 0
    Большое спасибо @Martin за ответ. cps кажется, делает трюк для меня. Только один вопрос: я использую TypeScript, поэтому какой должен быть тип onGetCameras потому что сейчас, когда я получаю yield cps(onGetCameras) , он жалуется, что context свойства отсутствует в типе, который я ему дал --- заставить это работать, я сделал это: yield cps(onGetCameras.bind(null)) , но я не уверен, что это правильный способ сделать это
  • 0
    У меня буквально 0 опыта работы с машинописью, но быстрый поиск в Google показал, что а) если для функции существует несколько определений типов и вы их не выполняете, тогда машинопись покажет вам только последнее (может объяснить, почему он жалуется на контекст) б) это интерфейс обратного вызова cps: interface CpsCallback<R> { (error: any, result: R): void; cancel?(): void; }
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню