NGRX - 单一效果的多项操作
NGRX - Multiple actions on single effect
这就是我的效果..
@Effect() uploadImages$ = this.actions$
.ofType(ProjectActions.UPLOAD_IMAGES)
.map(action => action.payload)
.flatMap(project => this.service.uploadImages(project))
.switchMap((project) => Observable.of(
this.imageActions.loadImages(),
this.projectActions.uploadImagesSuccess(project),
));
尝试在 uploadImagesSuccess 触发之前从 API 加载图像列表。
我尝试使用 .concatMap 和 .mergeMap 来代替 .switchMap,但事实并非如此。
对 Effects 和 Observables 还很陌生,从我所遇到的情况来看,没有什么能让我找到任何答案。
只需要一个接一个完成即可。
编辑 1
因此 loadImages() 会触发,一旦完成 API 调用,它就会触发 loadImagesSuccess()。我想我的目标是..
@Effect() uploadImages$ = this.actions$
.ofType(ProjectActions.UPLOAD_IMAGES)
.map(action => action.payload)
.flatMap(project => this.service.uploadImages(project))
.switchMap((project) => Observable.of(
this.imageActions.loadImages(),
this.imageActions.loadImagesSuccess(),
this.projectActions.uploadImagesSuccess(project),
));
从更一般的意义上讲,我正在将照片保存到 API 上的项目中。我想在 uploadImagesSuccess() 有效载荷到达我的选择器之前刷新我的 ImageState,并且由于 ImageState 没有及时更新而具有未定义的图像路径。
编辑 2
我通过这个解决方案来使用 ForkJoin,https://github.com/ngrx/effects/issues/64
@Effect() uploadImages$ = this.actions$
.ofType(ProjectActions.UPLOAD_IMAGES)
.map(action => action.payload)
.flatMap(project => {
let projectInfo$ = this.projectService.uploadImages(project);
let imageInfo$ = this.imageService.loadImages();
return Observable.forkJoin(projectInfo$, imageInfo$);
})
.mergeMap((results: any[]) => {
let myActions: any[] = [];
let actionGenerators = [
(data: any) => {
return this.projectActions.uploadImagesSuccess(data);
},
(data: any) => {
return this.imageActions.loadImagesSuccess(data);
}
];
results.forEach((data: any, index: number) => {
myActions.push(actionGenerators[index](data));
});
return Observable.from(myActions);
});
不确定这是否是解决此问题的最佳方法,但只要我延迟 API 调用以加载图像,它就可以工作。没有延迟,在保存新图像之前加载图像。目前我正在 API 方面延迟 loadImages()。
如果可能,我想要一个更好的方法来处理将 API 调用发送到 imageService.loadImages() 直到 projectService.uploadImages() returns。然后,一旦返回所有数据,就触发更新商店的操作。
建议使用 concat 而不是 forkJoin,以便等待一个 API 调用完成,然后再继续下一个。但这会破坏 results.Foreach() 因为结果不再在数组中。
使用连接:
@Effect() uploadImages$ = this.actions$
.ofType(ProjectActions.UPLOAD_IMAGES)
.map(action => action.payload)
.flatMap(project => this.service.uploadImages(project))
.switchMap((project) => Observable.concat(
this.imageActions.loadImages(),
this.projectActions.uploadImagesSuccess(project),
));
或来自:
@Effect() uploadImages$ = this.actions$
.ofType(ProjectActions.UPLOAD_IMAGES)
.map(action => action.payload)
.flatMap(project => this.service.uploadImages(project))
.switchMap((project) => Observable.from([
this.imageActions.loadImages(),
this.projectActions.uploadImagesSuccess(project)]
));
也许你可以试试这个。不要使用加载图片操作,只需在上传图片副作用中调用加载图片 api 即可。像这样:
@Effect() uploadImages$ = this.actions$
.ofType(ProjectActions.UPLOAD_IMAGES)
.map(action => action.payload)
.mergeMap(project => this.service.uploadImages(project)
.mergeMap(() => {
return this.otherService.loadImages()
.map((images) => this.projectActions.uploadImagesSuccess({ project: project, images: images))
}
));
然后你可以通过监听 UPLOAD_IMAGES_SUCCESS 动作让两个 reducer 更新状态:
export default function ProjectReducer (state = initialState, action: Action) {
switch (action.type) {
case UPLOAD_IMAGES_SUCCESS:
return // do your update with action.payload.project
default:
return state;
}
};
export default function ImagesReducer (state = initialState, action: Action) {
switch (action.type) {
case UPLOAD_IMAGES_SUCCESS:
return // do your update with action.payload.images
default:
return state;
}
};
您可以在 ngrx 示例应用程序中看到相同的模式。在两个减速器中 ADD_TO_CART 正在被监听:
https://github.com/btroncone/ngrx-examples/blob/master/shopping-cart/src/app/reducers/products.ts
https://github.com/btroncone/ngrx-examples/blob/master/shopping-cart/src/app/reducers/cart.ts
这就是我的效果..
@Effect() uploadImages$ = this.actions$
.ofType(ProjectActions.UPLOAD_IMAGES)
.map(action => action.payload)
.flatMap(project => this.service.uploadImages(project))
.switchMap((project) => Observable.of(
this.imageActions.loadImages(),
this.projectActions.uploadImagesSuccess(project),
));
尝试在 uploadImagesSuccess 触发之前从 API 加载图像列表。
我尝试使用 .concatMap 和 .mergeMap 来代替 .switchMap,但事实并非如此。
对 Effects 和 Observables 还很陌生,从我所遇到的情况来看,没有什么能让我找到任何答案。
只需要一个接一个完成即可。
编辑 1
因此 loadImages() 会触发,一旦完成 API 调用,它就会触发 loadImagesSuccess()。我想我的目标是..
@Effect() uploadImages$ = this.actions$
.ofType(ProjectActions.UPLOAD_IMAGES)
.map(action => action.payload)
.flatMap(project => this.service.uploadImages(project))
.switchMap((project) => Observable.of(
this.imageActions.loadImages(),
this.imageActions.loadImagesSuccess(),
this.projectActions.uploadImagesSuccess(project),
));
从更一般的意义上讲,我正在将照片保存到 API 上的项目中。我想在 uploadImagesSuccess() 有效载荷到达我的选择器之前刷新我的 ImageState,并且由于 ImageState 没有及时更新而具有未定义的图像路径。
编辑 2
我通过这个解决方案来使用 ForkJoin,https://github.com/ngrx/effects/issues/64
@Effect() uploadImages$ = this.actions$
.ofType(ProjectActions.UPLOAD_IMAGES)
.map(action => action.payload)
.flatMap(project => {
let projectInfo$ = this.projectService.uploadImages(project);
let imageInfo$ = this.imageService.loadImages();
return Observable.forkJoin(projectInfo$, imageInfo$);
})
.mergeMap((results: any[]) => {
let myActions: any[] = [];
let actionGenerators = [
(data: any) => {
return this.projectActions.uploadImagesSuccess(data);
},
(data: any) => {
return this.imageActions.loadImagesSuccess(data);
}
];
results.forEach((data: any, index: number) => {
myActions.push(actionGenerators[index](data));
});
return Observable.from(myActions);
});
不确定这是否是解决此问题的最佳方法,但只要我延迟 API 调用以加载图像,它就可以工作。没有延迟,在保存新图像之前加载图像。目前我正在 API 方面延迟 loadImages()。
如果可能,我想要一个更好的方法来处理将 API 调用发送到 imageService.loadImages() 直到 projectService.uploadImages() returns。然后,一旦返回所有数据,就触发更新商店的操作。
建议使用 concat 而不是 forkJoin,以便等待一个 API 调用完成,然后再继续下一个。但这会破坏 results.Foreach() 因为结果不再在数组中。
使用连接:
@Effect() uploadImages$ = this.actions$
.ofType(ProjectActions.UPLOAD_IMAGES)
.map(action => action.payload)
.flatMap(project => this.service.uploadImages(project))
.switchMap((project) => Observable.concat(
this.imageActions.loadImages(),
this.projectActions.uploadImagesSuccess(project),
));
或来自:
@Effect() uploadImages$ = this.actions$
.ofType(ProjectActions.UPLOAD_IMAGES)
.map(action => action.payload)
.flatMap(project => this.service.uploadImages(project))
.switchMap((project) => Observable.from([
this.imageActions.loadImages(),
this.projectActions.uploadImagesSuccess(project)]
));
也许你可以试试这个。不要使用加载图片操作,只需在上传图片副作用中调用加载图片 api 即可。像这样:
@Effect() uploadImages$ = this.actions$
.ofType(ProjectActions.UPLOAD_IMAGES)
.map(action => action.payload)
.mergeMap(project => this.service.uploadImages(project)
.mergeMap(() => {
return this.otherService.loadImages()
.map((images) => this.projectActions.uploadImagesSuccess({ project: project, images: images))
}
));
然后你可以通过监听 UPLOAD_IMAGES_SUCCESS 动作让两个 reducer 更新状态:
export default function ProjectReducer (state = initialState, action: Action) {
switch (action.type) {
case UPLOAD_IMAGES_SUCCESS:
return // do your update with action.payload.project
default:
return state;
}
};
export default function ImagesReducer (state = initialState, action: Action) {
switch (action.type) {
case UPLOAD_IMAGES_SUCCESS:
return // do your update with action.payload.images
default:
return state;
}
};
您可以在 ngrx 示例应用程序中看到相同的模式。在两个减速器中 ADD_TO_CART 正在被监听:
https://github.com/btroncone/ngrx-examples/blob/master/shopping-cart/src/app/reducers/products.ts
https://github.com/btroncone/ngrx-examples/blob/master/shopping-cart/src/app/reducers/cart.ts