NGRX - 单一效果的多项操作

时间:2017-07-25 02:36:00

标签: action effects ngrx

所以这是我的影响..

@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,但这似乎并不是它。

对于效果和观察者来说相当新鲜,而且从我所遇到的一切都没有引出任何答案。

只需要在另一个完成后开火。

修改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()。

如果可能的话,我希望有一种更好的方法来处理向imageService.loadImages()发送API调用,直到projectService.uploadImages()返回。然后,一旦返回所有数据,就触发操作以更新商店。

有人建议使用concat而不是forkJoin来等待一个API调用完成,然后再转到下一个。但这会破坏results.Foreach()因为结果不再是数组。

2 个答案:

答案 0 :(得分:1)

也许你可以试试这个。而不是使用加载图像操作,只需在上传图像副作用中执行加载图像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动作让两个reducers更新状态:

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示例应用程序中看到相同的模式。在两个Reducer中,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

答案 1 :(得分:0)

使用concat:

@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)]
        ));