如何在 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
函数时this
是null
。正如我从源代码和文档中看到的那样,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()
个参数会立即计算。
我有一个想法,根据职责分开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
函数时this
是null
。正如我从源代码和文档中看到的那样,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()
个参数会立即计算。