简体   繁体   English

如何在angular2应用中使用ngrx-effects从商店返回分页数据或从api服务返回新数据?

[英]How to return paginated data from the store OR new data from an api service using ngrx-effects in an angular2 app?

My question is a continuation of this excellent question and answer concerning the shape of paginated data in a redux store. 我的问题是一个延续这种出色的问题和答案就在终极版商店分页数据的形状。 I am using ngrx/store in an angular 2 app. 我在有角2应用程序中使用ngrx / store。

{
  entities: {
    users: {
      1: { id: 1, name: 'Dan' },
      42: { id: 42, name: 'Mary' }
    }
  },
  visibleUsers: {
    ids: [1, 42],
    isFetching: false,
    offset: 0
  }
}

Based on the above shape I believe if the offset (or page, sort, etc.) from an incoming request payload changed then the visible users would change as well as the user entities by calling the DB. 基于上述形状,我相信如果传入请求有效负载的偏移量(或页面,排序等)发生了变化,则可见用户以及通过调用DB的用户实体都将发生变化。 I have some actions and reducer functions to handle this and it works as expected. 我有一些操作和reducer函数来处理此问题,并且它按预期工作。 If the offset remains the same and the user is returning to the page the way they left it then the user entities should be returned by the store not the DB. 如果偏移量保持不变,并且用户正以其离开页面的方式返回页面,则用户实体应由商店而非数据库返回。

Where I am struggling is where to put that logic and which rxjs operators to use (still learning this). 我在努力的地方是放置该逻辑的位置以及要使用的rxjs运算符(仍在学习中)。

I think the correct place is an effect. 认为正确的地方是有效果的。 Here is what I have now in my angular2 app (I am injecting Actions, Store, and my UserService) that pulls new data every time the page is loaded. 这是我现在在angular2应用程序(正在注入Actions,Store和UserService)中拥有的内容,每次加载页面时,该应用程序都会提取新数据。

@Effect loadUsers$ = this.actions$
     .ofType('LOAD_USERS')
     .switchMap(() => this.userService.query()
         .map((results) => {
             return new LoadUsersSuccessAction(results);
         }))
     .catch(() => Observable.of(new LoadUsersFailureAction()));

My best idea is something like this: 我最好的主意是这样的:

@Effect loadUsers$ = this.actions$
     .ofType('LOAD_USERS')
     .withLatestFrom(this.store.select(state => state.visibleUsers.offset))
     .switchMap(([action, state]) => {
         //something that looks like this??
         //this syntax is wrong and I can't figure out how to access the action payload
         state.offset === payload.offset 
            ? this.store.select(state => state.entities.users) 
            : this.userService.query()
         }
         .map((results) => {
             return new LoadUsersSuccessAction(results);
         }))
     .catch(() => Observable.of(new LoadUsersFailureAction()));

Not sure how to make this work. 不知道如何使这项工作。 Thanks ahead. 谢谢你

I don't like answering my own questions but it took me quite a while to find the answer to this. 我不喜欢回答自己的问题,但是花了我一段时间才找到答案。 I won't accept this answer as I am not sure this is the best way to go about things (still learning the ins/outs). 我不接受这个答案,因为我不确定这是否是解决问题的最佳方法(仍在学习内容)。 It does however, work perfectly. 但是,它确实运行良好。

I found the correct syntax in a github gist . 我在github gist中找到了正确的语法。 This code does not match my example but it clearly demonstrates "2 options for conditional ngrx effects" by either returning a store or api observable using some sort of condition. 该代码与我的示例不匹配,但是通过返回使用某种条件可观察到的商店或api,它清楚地演示了“ 2个有条件的ngrx效果选项”。

Hope this helps someone. 希望这对某人有帮助。

Here it is: 这里是:

  @Effect()
  selectAndLoadStore$: Observable<Action> = this.actions$
    .ofType(storeActions.SELECT_AND_LOAD_STORE)
    .withLatestFrom(this.store.select(ngrx.storeState))
    .map(([action, storeState]) => [action.payload, storeState])
    .switchMap(([storeName, storeState]) => {
      const existsInStore = Boolean(storeState.urlNameMap[storeName]);
      return Observable.if(
        () => existsInStore,
        Observable.of(new storeActions.SetSelectedStore(storeName)),
        this.storeService.getByUrlName(storeName)
          .map(store => new storeActions.LoadSelectedStoreSuccess(store))
      );
    });

  @Effect()
  selectAndLoadStore$: Observable<Action> = this.actions$
    .ofType(storeActions.SELECT_AND_LOAD_STORE)
    .withLatestFrom(this.store.select(ngrx.storeState))
    .map(([action, storeState]) => [action.payload, storeState])
    .switchMap(([storeName, storeState]) => {
      const existsInStore = Boolean(storeState.urlNameMap[storeName]);
      let obs;
      if (existsInStore) {
        obs = Observable.of(new storeActions.SetSelectedStore(storeName));
      } else {
        obs = this.storeService.getByUrlName(storeName)
          .map(store => new storeActions.LoadSelectedStoreSuccess(store));
      }
      return obs;
    });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM