有没有办法一次调度动作?

时间:2019-12-10 11:19:04

标签: angular rxjs ngrx ngrx-effects

详细信息

我一直在从事从API获取数据的项目。为了获取这些数据,我将需要的东西存储在商店中。 例如,在商店中,我正在存储当前选择的时间段,地图的当前bbox以及正在从API中获取的数据。我需要实现的是,每当选定时期或地图的当前边界框发生变化时,都要更新商店中的数据。

为此,我为周期,BBox和统计创建了一个动作,一个减速器和一个效果。我遵循的逻辑如下,我也将其用于BBox和Stats。

代码

export interface IPeriodState {
  periods: Period[];
  isLoading: boolean;
  error: Error;
}

在化简器中,我只是改变状态而已。我的动作与此逻辑相同:

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)
    );
  }

摘要

是否有办法消除多个已分派的动作?

注意

您可以找到项目here的完整代码和项目here的演示

2 个答案:

答案 0 :(得分:2)

我建议提取何时分派LoadStatsAction动作的逻辑以避免重复的代码,它应该看起来像这样:

  @Effect() addPeriod$ = this.actions.pipe(
    ofType<PeriodActions>(PeriodActionTypes.ADD_PERIOD),
    map((action: AddPeriodAction) => new AddPeriodSuccessAction(action.payload)),
    catchError(error => of(new AddPeriodFailureAction(error)))
  );

  @Effect() removePeriod$ = this.actions.pipe(
    ofType<PeriodActions>(PeriodActionTypes.REMOVE_PERIOD),
    map((action: RemovePeriodAction) => new RemovePeriodSuccessAction(action.id)),
    catchError(error => of(new RemovePeriodFailureAction(error)))
  );

  @Effect() updatePeriod$ = this.actions.pipe(
    ofType<PeriodActions>(PeriodActionTypes.UPDATE_PERIOD),
    map((action: UpdatePeriodAction) => new UpdatePeriodSuccessAction(action.id, action.payload)),
    catchError(error => of(new UpdatePeriodFailureAction(error)))
  );

  @Effect() loadStats$ = this.actions.pipe(
      ofType(
        AddPeriodSuccessAction,
        RemovePeriodSuccessAction,
        UpdatePeriodSuccessAction
      ),
      mapTo(new LoadStatsAction())
  )

现在,您可以集中精力减少发送LoadStatsAction的时间,使用debounceTime(x)throttleTime(x) (可以在here中找到这些运算符之间的区别)

答案 1 :(得分:1)

如果我的问题没错,我想的问题是您想多次分发动作,但又不想将其添加到这3种效果中吗?在这种情况下,您可以执行以下操作:

我们可以在// The Employee now takes an Employee or Employee-like object // instead of separate arguments. class Employee { constructor({ name, gender, department, yy, email, skills }) { this.name = name; this.gender = gender; this.department = department; this.email = email; this.skills = skills || []; } addNewSkill(skill){ this.skills.push(skill); } } // Create an Employee. const employee = new Employee({ name: "John Doe", gender: "male", department: "CS", email: "john@doe.com" }); // Add a skill. employee.addNewSkill("coding"); // Turn employee to string and save to localStorage. localStorage.setItem("employee", JSON.stringify(employee)); // Parse the string back into an Employee-like object and // use that object to construct a new Employee. const retrievedEmployee = new Employee(JSON.parse(localStorage.getItem("employee"))) // Add another skill, using the Employee instance method. retrievedEmployee.addNewSkill("reading"); // Logs Employee having 2 skills, one added *before* we saved to localStorage // and another skill we added *after* we retrieved him from localStorage. console.log(retrievedEmployee); 运算符中侦听多个动作,在当前请求尚未满足时,使用ofTypeswitchMap取消多个请求。

exhaustMap