根据前一个动作的结果有条件地发送一个动作
Conditionally dispatch an action depending on result of previous action
我有两个操作:验证和更新。两者都可以独立分派,但我也希望如果分派更新操作,它首先分派验证操作,只有在没有验证的情况下才继续。
如果这是同步代码,它将类似于:
if (this.backendService.isValid(dataset)) {
this.backEndService.update(dataset)
}
两个动作的定义(以及对应的成功和错误动作):
export const validateDataset = createAction('[Datasets API] Validate Dataset', props<{ dataset: DataSetDto }>());
export const validateDatasetSuccess = createAction('[Datasets API] Validate Dataset Success', props<{ validationErrors: SgErrorMessage[]}>());
export const validateDatasetFail = createAction('[Datasets API] Validate Dataset Fail', props<{ error: string }>());
export const updateDataset = createAction('[Datasets API] Update Dataset', props<{ dataset: DataSetDto }>());
export const updateDatasetSuccess = createAction('[Datasets API] Update Dataset Success');
export const updateDatasetFail = createAction('[Datasets API] Update Dataset Fail', props<{ errorEntity: SgErrorEntity }>());
尝试 1
如果我有效果监听 updateDataset
并尝试首先发送 validateDataset
它似乎永远不会在应用 .pipe()
时被使用(并且可能在这里我应该使用选择器像 hasValidationErrors
返回 bool 而不是同时使用 filter
运算符):
updateDataset$ = createEffect(() => {
return this.actions$.pipe(
ofType(DatasetApiActions.updateDataset),
mergeMap(action => of(DatasetPageActions.validateDataset({dataset: action.dataset})).pipe(
withLatestFrom(this.store.pipe(select(getValidationErrors))),
filter(([action, validationErrors]) => validationErrors.length > 0),
mergeMap(([action, validationErrors]) => this.datasetService.editDataSet(action.dataset).pipe(
map(() => DatasetApiActions.updateDatasetSuccess()),
catchError(error => of(DatasetApiActions.updateDatasetFail({error})))
))
))
);
});
尝试 2
我尝试将其拆分为 saveDataset
操作,该操作应按顺序调用 validateDataset
和 updateDataset
操作,并将 updateDataset
过滤为仅运行 如果 validationErrors
状态为空。我使用了 concatMap
,因此操作可以按顺序触发,它们可能是,但 success/fail 响应稍后出现,因此无法使用验证数据:
saveDataset$ = createEffect(() => {
return this.actions$.pipe(
ofType(DatasetPageActions.saveDataset),
concatMap(action => concat(
of(DatasetPageActions.validateDataset({dataset: action.dataset})),
of(DatasetApiActions.updateDataset({dataset: action.dataset}))
))
);
});
updateDataset$ = createEffect(() => {
return this.actions$.pipe(
ofType(DatasetApiActions.updateDataset),
withLatestFrom(this.store.pipe(select(getValidationErrors))),
filter(([action, validationErrors]) => validationErrors.length == 0),
tap(([action, validationErrors]) => console.log("validationErrors: " + validationErrors))
);
}, {dispatch: false});
也许我考虑的方式不对,应该将验证构建为异步表单验证,但我仍然认为这个问题是有效的。
我遇到的问题是我无法向 validateDatasetSuccess
操作添加效果来触发 updateDataset
操作,因为它可能由用户单独调度(并且不仅通过保存)。有什么办法可以实现这种行为吗?
你可以试试这个:
updateDataset$ = createEffect(() => {
return this.actions$.pipe(
ofType(DatasetApiActions.updateDataset),
// dispatch the `validate` action
tap(action => this.store.dispatch(DatasetPageActions.validateDataset({dataset: action.dataset}))),
switchMap(
action => this.store.pipe(
select(getValidationErrors),
// we want to skip the current state
// after all, the store is just a `BehaviorSubject`,
// so subscribing to it will return the current state
skip(1),
filter(validationErrors => /* ... your condition here ... */),
mapTo(action),
),
),
mergeMap(
action => this.datasetService.editDataSet(action.dataset).pipe(
map(() => DatasetApiActions.updateDatasetSuccess()),
catchError(error => of(DatasetApiActions.updateDatasetFail({error})))
)
)
);
});
我有两个操作:验证和更新。两者都可以独立分派,但我也希望如果分派更新操作,它首先分派验证操作,只有在没有验证的情况下才继续。
如果这是同步代码,它将类似于:
if (this.backendService.isValid(dataset)) {
this.backEndService.update(dataset)
}
两个动作的定义(以及对应的成功和错误动作):
export const validateDataset = createAction('[Datasets API] Validate Dataset', props<{ dataset: DataSetDto }>());
export const validateDatasetSuccess = createAction('[Datasets API] Validate Dataset Success', props<{ validationErrors: SgErrorMessage[]}>());
export const validateDatasetFail = createAction('[Datasets API] Validate Dataset Fail', props<{ error: string }>());
export const updateDataset = createAction('[Datasets API] Update Dataset', props<{ dataset: DataSetDto }>());
export const updateDatasetSuccess = createAction('[Datasets API] Update Dataset Success');
export const updateDatasetFail = createAction('[Datasets API] Update Dataset Fail', props<{ errorEntity: SgErrorEntity }>());
尝试 1
如果我有效果监听 updateDataset
并尝试首先发送 validateDataset
它似乎永远不会在应用 .pipe()
时被使用(并且可能在这里我应该使用选择器像 hasValidationErrors
返回 bool 而不是同时使用 filter
运算符):
updateDataset$ = createEffect(() => {
return this.actions$.pipe(
ofType(DatasetApiActions.updateDataset),
mergeMap(action => of(DatasetPageActions.validateDataset({dataset: action.dataset})).pipe(
withLatestFrom(this.store.pipe(select(getValidationErrors))),
filter(([action, validationErrors]) => validationErrors.length > 0),
mergeMap(([action, validationErrors]) => this.datasetService.editDataSet(action.dataset).pipe(
map(() => DatasetApiActions.updateDatasetSuccess()),
catchError(error => of(DatasetApiActions.updateDatasetFail({error})))
))
))
);
});
尝试 2
我尝试将其拆分为 saveDataset
操作,该操作应按顺序调用 validateDataset
和 updateDataset
操作,并将 updateDataset
过滤为仅运行 如果 validationErrors
状态为空。我使用了 concatMap
,因此操作可以按顺序触发,它们可能是,但 success/fail 响应稍后出现,因此无法使用验证数据:
saveDataset$ = createEffect(() => {
return this.actions$.pipe(
ofType(DatasetPageActions.saveDataset),
concatMap(action => concat(
of(DatasetPageActions.validateDataset({dataset: action.dataset})),
of(DatasetApiActions.updateDataset({dataset: action.dataset}))
))
);
});
updateDataset$ = createEffect(() => {
return this.actions$.pipe(
ofType(DatasetApiActions.updateDataset),
withLatestFrom(this.store.pipe(select(getValidationErrors))),
filter(([action, validationErrors]) => validationErrors.length == 0),
tap(([action, validationErrors]) => console.log("validationErrors: " + validationErrors))
);
}, {dispatch: false});
也许我考虑的方式不对,应该将验证构建为异步表单验证,但我仍然认为这个问题是有效的。
我遇到的问题是我无法向 validateDatasetSuccess
操作添加效果来触发 updateDataset
操作,因为它可能由用户单独调度(并且不仅通过保存)。有什么办法可以实现这种行为吗?
你可以试试这个:
updateDataset$ = createEffect(() => {
return this.actions$.pipe(
ofType(DatasetApiActions.updateDataset),
// dispatch the `validate` action
tap(action => this.store.dispatch(DatasetPageActions.validateDataset({dataset: action.dataset}))),
switchMap(
action => this.store.pipe(
select(getValidationErrors),
// we want to skip the current state
// after all, the store is just a `BehaviorSubject`,
// so subscribing to it will return the current state
skip(1),
filter(validationErrors => /* ... your condition here ... */),
mapTo(action),
),
),
mergeMap(
action => this.datasetService.editDataSet(action.dataset).pipe(
map(() => DatasetApiActions.updateDatasetSuccess()),
catchError(error => of(DatasetApiActions.updateDatasetFail({error})))
)
)
);
});