在 Ngrx Effect 中有条件地返回 Observable<Action>
Conditonally returning Observable<Action> within Ngrx Effect
我目前正在重构我的代码以包含 ngrx 商店。为了最大程度地减少 API 调用我的 LoadDeals() 操作的次数,如果商店为空,我将检查效果。只有当它为空时,才继续进行 API 调用。我首先尝试使用在 SO () 上找到的这种模式。
我意识到缺点是,如果存储中有数据,每个 LoadDeals() 调用都会被忽略。为了有可能强制加载,我在 LoadDeals() class 中包含了一个可选的布尔有效负载。如果设置为 true,请调用 API.
这是我的第一次尝试
@Effect() loadDeals$: Observable<Action> = this._actions$.pipe(
ofType<LoadDeals>(actions.LOAD_DEALS),
withLatestFrom(this._store.pipe(select(getDealsLoaded))),
switchMap(([action, hasLoaded]) => {
if (!hasLoaded || action.force) {
return this._deals.deals.pipe(
map(deals => new LoadDealsSuccess(deals)),
catchError(error => of(new LoadDealsFail(error)))
);
} else {
return of(new LoadDealsSkip());
}
})
);
但这会产生以下错误:
Argument of type '([action, hasLoaded]: [LoadDeals, boolean]) => Observable<LoadDealsSuccess | LoadDealsFail> | Observable<LoadDealsSkip>' is not assignable to parameter of type '(value: [LoadDeals, boolean], index: number) => ObservableInput<LoadDealsSuccess | LoadDealsFail>'.
Type 'Observable<LoadDealsSuccess | LoadDealsFail> | Observable<LoadDealsSkip>' is not assignable to type 'ObservableInput<LoadDealsSuccess | LoadDealsFail>'.
Type 'Observable<LoadDealsSkip>' is not assignable to type 'ObservableInput<LoadDealsSuccess | LoadDealsFail>'.
Type 'Observable<LoadDealsSkip>' is not assignable to type 'Iterable<LoadDealsSuccess | LoadDealsFail>'.
Property '[Symbol.iterator]' is missing in type 'Observable<LoadDealsSkip>'.
这是我的 deals.actions.ts
import { Action } from '@ngrx/store';
import { ITmsCpRecord } from '@models/cp';
export enum DealsActionTypes {
LOAD_DEALS = '[Deals] Load Deals',
LOAD_DEALS_FAIL = '[Deals API] Load Deals Fail',
LOAD_DEALS_SUCCESS = '[Deals API] Load Deals Success',
LOAD_DEALS_SKIP = '[Deals Store] Load Deals Skip (cached)'
}
export class LoadDeals implements Action {
readonly type = DealsActionTypes.LOAD_DEALS;
constructor(public force: boolean = false) {}
}
export class LoadDealsFail implements Action {
readonly type = DealsActionTypes.LOAD_DEALS_FAIL;
constructor(public payload: any) {}
}
export class LoadDealsSuccess implements Action {
readonly type = DealsActionTypes.LOAD_DEALS_SUCCESS;
constructor(public payload: ITmsCpRecord[]) {}
}
export class LoadDealsSkip implements Action {
readonly type = DealsActionTypes.LOAD_DEALS_SKIP;
}
// action types
export type DealsAction = LoadDeals|LoadDealsFail|LoadDealsSuccess|LoadDealsSkip;
所以我将它拆分成单独的效果器来监听相同的动作但使用不同的过滤器运算符。这很好用。虽然我不想拆分它,因为它是一些冗余代码。
有人看到我的错误了吗?干杯
@Effect() loadDeals$: Observable<Action> = this._actions$.pipe(
ofType<LoadDeals>(actions.LOAD_DEALS),
withLatestFrom(this._store.pipe(select(getDealsLoaded))),
filter(([action, hasLoaded]) => !hasLoaded || action.force),
switchMap(() => {
return this._deals.deals.pipe(
map(deals => new LoadDealsSuccess(deals)),
catchError(error => of(new LoadDealsFail(error)))
);
})
);
@Effect() loadDealsSkip$: Observable<Action> = this._actions$.pipe(
ofType<LoadDeals>(actions.LOAD_DEALS),
withLatestFrom(this._store.pipe(select(getDealsLoaded))),
filter(([action, hasLoaded]) => hasLoaded && !action.force),
switchMap(() => of(new LoadDealsSkip()))
);
您可能不喜欢这个答案,但我建议为此创建 2 个操作。
一个像你已经拥有的加载动作,另一个强制加载动作。
这也意味着创建 2 个效果,但在第二个中,您不必从商店select。
我目前正在重构我的代码以包含 ngrx 商店。为了最大程度地减少 API 调用我的 LoadDeals() 操作的次数,如果商店为空,我将检查效果。只有当它为空时,才继续进行 API 调用。我首先尝试使用在 SO () 上找到的这种模式。
我意识到缺点是,如果存储中有数据,每个 LoadDeals() 调用都会被忽略。为了有可能强制加载,我在 LoadDeals() class 中包含了一个可选的布尔有效负载。如果设置为 true,请调用 API.
这是我的第一次尝试
@Effect() loadDeals$: Observable<Action> = this._actions$.pipe(
ofType<LoadDeals>(actions.LOAD_DEALS),
withLatestFrom(this._store.pipe(select(getDealsLoaded))),
switchMap(([action, hasLoaded]) => {
if (!hasLoaded || action.force) {
return this._deals.deals.pipe(
map(deals => new LoadDealsSuccess(deals)),
catchError(error => of(new LoadDealsFail(error)))
);
} else {
return of(new LoadDealsSkip());
}
})
);
但这会产生以下错误:
Argument of type '([action, hasLoaded]: [LoadDeals, boolean]) => Observable<LoadDealsSuccess | LoadDealsFail> | Observable<LoadDealsSkip>' is not assignable to parameter of type '(value: [LoadDeals, boolean], index: number) => ObservableInput<LoadDealsSuccess | LoadDealsFail>'.
Type 'Observable<LoadDealsSuccess | LoadDealsFail> | Observable<LoadDealsSkip>' is not assignable to type 'ObservableInput<LoadDealsSuccess | LoadDealsFail>'.
Type 'Observable<LoadDealsSkip>' is not assignable to type 'ObservableInput<LoadDealsSuccess | LoadDealsFail>'.
Type 'Observable<LoadDealsSkip>' is not assignable to type 'Iterable<LoadDealsSuccess | LoadDealsFail>'.
Property '[Symbol.iterator]' is missing in type 'Observable<LoadDealsSkip>'.
这是我的 deals.actions.ts
import { Action } from '@ngrx/store';
import { ITmsCpRecord } from '@models/cp';
export enum DealsActionTypes {
LOAD_DEALS = '[Deals] Load Deals',
LOAD_DEALS_FAIL = '[Deals API] Load Deals Fail',
LOAD_DEALS_SUCCESS = '[Deals API] Load Deals Success',
LOAD_DEALS_SKIP = '[Deals Store] Load Deals Skip (cached)'
}
export class LoadDeals implements Action {
readonly type = DealsActionTypes.LOAD_DEALS;
constructor(public force: boolean = false) {}
}
export class LoadDealsFail implements Action {
readonly type = DealsActionTypes.LOAD_DEALS_FAIL;
constructor(public payload: any) {}
}
export class LoadDealsSuccess implements Action {
readonly type = DealsActionTypes.LOAD_DEALS_SUCCESS;
constructor(public payload: ITmsCpRecord[]) {}
}
export class LoadDealsSkip implements Action {
readonly type = DealsActionTypes.LOAD_DEALS_SKIP;
}
// action types
export type DealsAction = LoadDeals|LoadDealsFail|LoadDealsSuccess|LoadDealsSkip;
所以我将它拆分成单独的效果器来监听相同的动作但使用不同的过滤器运算符。这很好用。虽然我不想拆分它,因为它是一些冗余代码。
有人看到我的错误了吗?干杯
@Effect() loadDeals$: Observable<Action> = this._actions$.pipe(
ofType<LoadDeals>(actions.LOAD_DEALS),
withLatestFrom(this._store.pipe(select(getDealsLoaded))),
filter(([action, hasLoaded]) => !hasLoaded || action.force),
switchMap(() => {
return this._deals.deals.pipe(
map(deals => new LoadDealsSuccess(deals)),
catchError(error => of(new LoadDealsFail(error)))
);
})
);
@Effect() loadDealsSkip$: Observable<Action> = this._actions$.pipe(
ofType<LoadDeals>(actions.LOAD_DEALS),
withLatestFrom(this._store.pipe(select(getDealsLoaded))),
filter(([action, hasLoaded]) => hasLoaded && !action.force),
switchMap(() => of(new LoadDealsSkip()))
);
您可能不喜欢这个答案,但我建议为此创建 2 个操作。 一个像你已经拥有的加载动作,另一个强制加载动作。
这也意味着创建 2 个效果,但在第二个中,您不必从商店select。