如何在 class 中使用 Redux-Saga

How to use Redux-Saga inside a class

我有一个想法,根据职责分开sagas。我已经为 saga 处理程序创建了一个基础 class,如下所示。

 export class BaseSagaHandler {

  static isGenerator(fn) {
    return fn.endsWith('Gen');
  }

  forkAllSagaFunctions() {
    const sagaFuncs = [];
    const functions = Object.getOwnPropertyNames(this.constructor.prototype);
    functions.forEach(func => {
      if (BaseSagaHandler.isGenerator(String(func))) {
        sagaFuncs.push(fork([this, this[func]]));
      }
    });
    return sagaFuncs;
  }
}

从上面的代码可以看出,我坚持约定,我们需要将所有以Gen结尾的方法都用作Sagas。 这是 child class

的示例
export class LocaleSaga extends BaseSagaHandler {
  private localeService: ILocaleService;

  constructor(localeService: ILocaleService) {
    super();
    this.localeService = localeService;
  }

  public* setCurrentLocale(locale) {
    yield call([this, this.localeService.setCurrentLocale], locale);
    yield put(WITH_PAYLOAD(SUCCESS(ACTION_TYPES.SET_LOCALE), locale));
  }

  public* setLocaleSagaGen() {
    yield takeLatest(REQUEST(ACTION_TYPES.SET_LOCALE), this.setCurrentLocale);
  }
}

此 class 以下列方式实例化。

const diContainer = rootDiContainer;
const localeSagas = new LocaleSaga(diContainer.get<ILocaleService>(LOCALE_SERVICE_TYPE)).forkAllSagaFunctions();
export default function* rootSaga() {
  yield all([
    localeSagas
  ]);
}

所以基本上我们监听一个特定的动作而不是调用一个函数。但是我在这条线上遇到了问题。

yield takeLatest(REQUEST(ACTION_TYPES.SET_LOCALE), this.setCurrentLocale);

就我通过class方法而言,当它到达setCurrentLocale函数时thisnull。正如我从源代码和文档中看到的那样,take* 方法不支持传递上下文,但是 fork,call 函数允许将 context 与函数一起传递。

有什么方法可以在 class 的上下文中传递 class 方法引用?

P.S。请让我知道我的想法是否有任何缺陷或没有任何意义。

谢谢。

更新

感谢 Andrey Moiseev 的 回答,我决定将两种方法组合成一个具有匿名生成器函数的方法,如下所示。

public* setLocaleSagaGen() {
    const context = this;
    yield takeEvery(REQUEST(ACTION_TYPES.SET_LOCALE), function* (locale) {
      const result = yield call([context.localeService, context.localeService.setCurrentLocale], locale);
      yield put(WITH_PAYLOAD(SUCCESS(ACTION_TYPES.SET_LOCALE), result));
    });
  }

在Javascript, this depends on where you're calling the function from.

问题是您传递给 takeLatest() 的 saga 稍后 从 redux-saga 内部调用。除非 redux-saga 接受 context,保存它,然后手动将其提供为 this(不幸的是它没有),否则它不起作用。

我看到两个可能的选择。

使用标准 takeLatest()

  • 在函数作用域中将 this 保存为 context
  • 将内联 saga 传递给 takeLatest()。这个 saga 是一个可以访问 context.
  • 的闭包

代码:

public* setLocaleSagaGen() {
  const context = this
  yield takeLatest(REQUEST(ACTION_TYPES.SET_LOCALE), function*() {
    yield call([context, context.setCurrentLocale])
  })
}

使用自定义 takeLatest()

在 redux-saga 文档中有一个 example implementation of takeLatest()。我修改它以接受并传递上下文:

const takeLatestWithContext = (patternOrChannel, [context, saga], ...args) => fork(function*() {
  let lastTask
  while (true) {
    const action = yield take(patternOrChannel)
    if (lastTask) {
      yield cancel(lastTask) // cancel is no-op if the task has already terminated
    }
    lastTask = yield fork([context, saga], ...args.concat(action))
  }
})

所以它可以像这样使用:

  public* setLocaleSagaGen() {
    const context = this
    yield takeLatest(REQUEST(ACTION_TYPES.SET_LOCALE), [this.context, this.setCurrentLocale]);
  }

在这种情况下,不需要保存 this,因为 takeLatest() 个参数会立即计算。