【发布时间】:2019-12-10 11:19:04
【问题描述】:
详情
我一直在从事一个从 API 获取数据的项目。为了获取这些数据,我将我需要的东西存储在商店中。 例如,在商店中,我正在存储当前选择的时间段、地图的当前 bbox 以及从 API 获取的数据。我需要实现的是每次选择的时间段或地图的当前边界框发生变化时,更新store中的数据。
为此,我为 Periods、BBox 和 Stats 创建了一个 Action、一个 Reducer 和一个 Effect。我遵循的逻辑如下,我也将它用于 BBox 和 Stats。
代码
export interface IPeriodState {
periods: Period[];
isLoading: boolean;
error: Error;
}
在 reducer 中,我只是改变状态,仅此而已。我的行为在这一点上是相同的逻辑:
import { Action } from "@ngrx/store";
import { Period } from "../../models/Period";
export enum PeriodActionTypes {
ADD_PERIOD = "[Period] Add Period",
ADD_PERIOD_SUCCESS = "[Period] Add Period Success",
ADD_PERIOD_FAILURE = "[Period] Add Period Failure",
REMOVE_PERIOD = "[Period] Remove Period",
REMOVE_PERIOD_SUCCESS = "[Period] Remove Period Success",
REMOVE_PERIOD_FAILURE = "[Period] Remove Period Failure",
UPDATE_PERIOD = "[Period] Update Period",
UPDATE_PERIOD_SUCCESS = "[Period] Update Period Success",
UPDATE_PERIOD_FAILURE = "[Period] Update Period Failure"
}
// Add Period
export class AddPeriodAction implements Action {
readonly type = PeriodActionTypes.ADD_PERIOD;
constructor(public payload: Period) {}
}
export class AddPeriodSuccessAction implements Action {
readonly type = PeriodActionTypes.ADD_PERIOD_SUCCESS;
constructor(public payload: Period) {}
}
export class AddPeriodFailureAction implements Action {
readonly type = PeriodActionTypes.ADD_PERIOD_FAILURE;
constructor(public error: Error) {}
}
// Remove Period
export class RemovePeriodAction implements Action {
readonly type = PeriodActionTypes.REMOVE_PERIOD;
constructor(public id: string) {}
}
export class RemovePeriodSuccessAction implements Action {
readonly type = PeriodActionTypes.REMOVE_PERIOD_SUCCESS;
constructor(public id: string) {}
}
export class RemovePeriodFailureAction implements Action {
readonly type = PeriodActionTypes.REMOVE_PERIOD_FAILURE;
constructor(public error: Error) {}
}
// Update Period
export class UpdatePeriodAction implements Action {
readonly type = PeriodActionTypes.UPDATE_PERIOD;
constructor(public id: string, public payload: Period) {}
}
export class UpdatePeriodSuccessAction implements Action {
readonly type = PeriodActionTypes.UPDATE_PERIOD_SUCCESS;
constructor(public id: string, public payload: Period) {}
}
export class UpdatePeriodFailureAction implements Action {
readonly type = PeriodActionTypes.UPDATE_PERIOD_FAILURE;
constructor(public error: Error) {}
}
export type PeriodActions =
| AddPeriodAction
| AddPeriodSuccessAction
| AddPeriodFailureAction
| RemovePeriodAction
| RemovePeriodSuccessAction
| RemovePeriodFailureAction
| UpdatePeriodAction
| UpdatePeriodSuccessAction
| UpdatePeriodFailureAction;
现在在效果中,我正在调度多个动作。例如:
//imports omitted
@Injectable()
export class PeriodEffect {
constructor(private actions: Actions) {}
@Effect() addPeriod$ = this.actions.pipe(
ofType<PeriodActions>(PeriodActionTypes.ADD_PERIOD),
mergeMap((action: AddPeriodAction) => [
new AddPeriodSuccessAction(action.payload),
new LoadStatsAction()
]),
catchError(error => of(new AddPeriodFailureAction(error)))
);
@Effect() removePeriod$ = this.actions.pipe(
ofType<PeriodActions>(PeriodActionTypes.REMOVE_PERIOD),
mergeMap((action: RemovePeriodAction) => [
new RemovePeriodSuccessAction(action.id),
new LoadStatsAction()
]),
catchError(error => of(new RemovePeriodFailureAction(error)))
);
@Effect() updatePeriod$ = this.actions.pipe(
ofType<PeriodActions>(PeriodActionTypes.UPDATE_PERIOD),
mergeMap((action: UpdatePeriodAction) => [
new UpdatePeriodSuccessAction(action.id, action.payload),
new LoadStatsAction()
]),
catchError(error => of(new UpdatePeriodFailureAction(error)))
);
}
问题
我的问题是我多次发送了LoadStatsAction,因为每次网站发生变化时,我都需要在商店中获取新数据。让我们看看我的period-selector 组件。一旦期间发生变化,我将使用以下代码管理此更改:
constructor(private moment: MomentPipe, private store: Store<AppState>) {
this.currentPeriod = new Period(
id(),
new Date(2017, 9, 1),
new Date(2018, 9, 1)
);
this.store.dispatch(new AddPeriodAction(this.currentPeriod));
}
ngOnInit() {}
ngOnDestroy() {
this.store.dispatch(new RemovePeriodAction(this.currentPeriod.id));
}
updateCurrentPeriod(period: IPeriod) {
this.currentPeriod._minDate = period.minDate;
this.currentPeriod._maxDate = period.maxDate;
this.store.dispatch(
new UpdatePeriodAction(this.currentPeriod.id, this.currentPeriod)
);
}
总结
有没有办法摆脱多个分派的动作?
注意
【问题讨论】:
-
我们能否为
updatePeriodSuccess$再创建一个效果,并且我们可以随时使用 switchMap 或 exhaustMap 到 LoadStatsAction 并取消/减少调用? -
我对 loadStats 有影响,就在这里。这是你想说的吗?而不是 mergeMap 使用
switchMap或exhaustMap?@Effect() loadStats$ = this.actions.pipe( ofType<StatsActions>(StateActionTypes.LOAD_STATS), mergeMap(() => this.apiService.getGlobalStats().pipe( map((data: IGlobalStats) => new LoadStatsSuccessAction(data)), catchError(error => of(new LoadStatsFailureAction(error))) ) ) );
标签: angular rxjs ngrx ngrx-effects