NGRX, Rxjs: что является лучшим решением для этого случая? Наблюдаемый в действии? - PullRequest
0 голосов
/ 19 июня 2019

В моем приложении у меня есть следующий случай, я хочу знать, как это сделать лучше:

// the effects function
this.user$ = this.actions$.pipe(
  ofType(UserActions.FETCH_USER),
  switchMap((_) => {
    return userService.getUser().pipe(
      map((res) => {
        return new UserActions.FetchUserSuccess(this.transformUserResData(res));
      }),
      catchError(() => {
        return observableOf(new UserActions.FetchUserFail());
      })
    );
  })
);

это простая функция эффекта, единственная точка нуждаупомянуто для случая success перед передачей данных ответа в функцию FetchUserSuccess в качестве полезной нагрузки.Мне нужно преобразовать это.И функция преобразования выглядит следующим образом:

  private transformUserResData(users: User[]): UserInfo[] {
    let groupIDNames: Array<IdNameMap>;
    this.groupStoreService.groupIDNames$.subscribe((res) => {
      groupIDNames = res; // array of {Id: "id", Name: "name"} object
    })
    return users.map((each) => {
      return {
        id: each.id,
        title: each.title,
        category: each.category, 
        groupName: groupIDNames.find(current => current.Id === each.groupID).Name
      };
    })       
  }

Как вы можете видеть, исходные данные преобразования являются массивом пользователя, и у каждого пользователя есть свойство с именем gruopID, которое просто означаетпользователь принадлежит к какой группе.

А целью функции преобразования является отображение groupID на groupName, я хочу добавить информацию об имени группы в объект пользователя.Четкая цель, верно?

И здесь есть один сложный момент: данные идентификатора группы и сопоставления имен являются наблюдаемыми.Фактически это значения состояния, выбранные из хранилища NGRX с помощью метода store.select в качестве значения this.groupStoreService.groupIDNames$.

Итак, мое текущее решение размещено здесь, вы можете видеть, что я подписываюсь на Observable и получаю данные как groupIDNames.И использовать его при последующем разборе.

Это может работать, поскольку возвращаемое значение this.groupStoreService.groupIDNames$ из store.select имеет тип SubjectBehavior (эта точка подтверждена в моем другом посте), поэтому функция обратного вызова субъекта является синхронизированной.

Это сработало, но я знаю, что это не лучшая практика.Поэтому я хочу знать, как улучшить его по-другому.

Я думал использовать следующий метод:

  private transformUserResData(users: User[]): Observable<UserInfo[]> {
    this.groupStoreService.groupIDNames$
       .pipe(map((groupIDNames) => {
          return users.map((each) => {
            return {
              id: each.id,
              title: each.title,
              category: each.category, 
              groupName: groupIDNames.find(current => current.Id === each.groupID).Name
           };
         })  
      }))     
  }

Но в этом случае функция преобразования вернет Observable, а Observable будет передано в действие с избыточностью.Я не знаю, что это лучшая практика для редукса.

Есть ли еще более разумное решение?Спасибо

1 Ответ

1 голос
/ 19 июня 2019

Вы можете немного более оперативно обновить свой код, составив хранилище ngrx, которое можно увидеть с помощью ответа API, например:

// the effects function
    this.user$ = this.actions$.pipe(
      ofType(UserActions.FETCH_USER),
      switchMap((_) => {
        return userService.getUser()
                         .pipe(
                                //lets transform the data
                                mergeMap((users: User[]) => {
                                  return this.groupStoreService.groupIDNames$
                                             .pipe(
                                               map((groupIDNames: Array<IdNameMap>) => {
                                                  return users.map((each) => {
                                                    return {
                                                      id: each.id,
                                                      title: each.title,
                                                      category: each.category, 
                                                      groupName: groupIDNames.find(current => current.Id === each.groupID).Name
                                                    };
                                                  });
                                               })
                                             );
                                }),
                                map((userInfos: UserInfo[]) => {
                                  return new UserActions.FetchUserSuccess(userInfos);
                                }),
                                catchError(() => {
                                  return observableOf(new UserActions.FetchUserFail());
                                })
                          );
      })
    );

Если вы хотите избежать вложения операторов, вы также можете написать так:

// the effects function
    this.user$ = this.actions$.pipe(
      ofType(UserActions.FETCH_USER),
      switchMap((_) => {
        return userService.getUser()
                         .pipe(
                                mergeMap((users: User[]) => {
                                  return combineLatest(of(users), this.groupStoreService.groupIDNames$.pipe(take(1)));
                                }),
                                map(([users, groupIDNames]) => {
                                  //project [map] your users to userInfo
                                  const userInfos = users.map((each) => {
                                                                return {
                                                                  id: each.id,
                                                                  title: each.title,
                                                                  category: each.category, 
                                                                  groupName: groupIDNames.find(current => current.Id === each.groupID).Name
                                                                };
                                                              });
                                  return new UserActions.FetchUserSuccess(userInfos);

                                }),                                
                                catchError(() => {
                                  return observableOf(new UserActions.FetchUserFail());
                                })
                          );
      })
    );
...