@ngrx使用.single

时间:2017-11-08 15:04:24

标签: javascript angular redux rxjs ngrx

我想返回一个Observable,它是从我商店的一系列对象中选择的。我想使用.single运算符,因为如果存在少于或多于1个对象,这将抛出异常。我无法让它工作,因为我的商店正在返回一个数组而不是一个可观察的数组。我知道我可以在阵列上使用.filter,但我想了解为什么我无法使用它。我甚至尝试过使用选择器。

我的App减速器有:

export interface AppState {
  batStores: fromBatStores.State;
}

export const reducers: ActionReducerMap<AppState> = {
  batStores: fromBatStores.batStoresReducer,
};

我模块的缩减器:

export interface State {
  batStores: BatStore[];
}

const initialState = {
  batStores: [
    new BatStore(0, 0, true, 'Cell 11', 11, 11),
    new BatStore(1, 0, false, 'Cel 12', 12, 11),
    new BatStore(2, 0, true, 'Cel 13', 13, 11),
    new BatStore(2, 0, true, 'Cel 14', 14, 11),
  ]
};

export const selectBatStores = (state: fromApp.AppState) => state.batStores;
export const selectBatStoresBatStores = createSelector(selectBatStores, (state: State) => state.batStores);

现在我在ngOnInit中尝试这样的事情:

ngOnInit() {
  const editId = 11;
  const batStore$: Observable<BatStore> = this.store.select(fromBatStores.selectBatStoresBatStores)
    .single(bs => bs.number === editId);

  this.batStore$ = batStore$;
}

PhpStorm说数字属性在BatStore []上不存在。我不明白,因为在example documentation单一也被用作可观察数组的运算符。

更新

看完答案后,仍然很困惑。为了测试,我写了这样的函数:

getBatStore(id: number) {
  const versionA$ = this.store.select(fromBatStores.selectBatStoresBatStores)
    .switchMap((batStores: BatStore[]) => Observable.from(batStores))
    .filter((bs: BatStore) => {
      console.log('Analyzing ', bs);
      console.log('Result ', bs.number === id);
      return bs.number === id;
    });

  const versionB$ = this.store.select(fromBatStores.selectBatStoresBatStores)
    .switchMap((batStores: BatStore[]) => Observable.from(batStores))
    .single((bs: BatStore) => {
      console.log('Analyzing ', bs);
      console.log('Result ', bs.number === id);
      return bs.number === id;
    });

  console.log('VersionA: ', versionA$);
  console.log('VersionB: ', versionB$);

  console.log('Same? ', versionA$ === versionB$);

  return versionB$;
}

两个版本都向控制台输出相同的内容。在我的视图中使用异步管道时,VersionA不起作用,版本B没有。代码编译,PhpStorm没有抱怨。

3 个答案:

答案 0 :(得分:1)

我理解你的困惑,PhpStorm说得对,&#34;数字属性在BatStore []&#34;上不存在。示例文档也是正确的。这里的关键点是来自RxJs的这个example,你需要知道Observable.from([array])是如何工作的。 Observable.from([array])创造了一个&#34;冷&#34;可观察的,为阵列中的每个项目进行一次发射。因此,结果Observable的类型为 number ,而不是array类型,如您所见:

const source: Observable<number> = Rx.Observable.from([1,2,3,4,5]);

您在商店中遇到的ObservableObservable类型Array。例如,如果使用运算符Observable.of,则会发出数组,而不是数组的每个项目:

const source: Observable<number[]> = Rx.Observable.of([1,2,3,4,5]);

说,我会做一个Array.filter,对我而言,它比Observable流上的任何其他转换更好。

如果您有任何疑问,请告诉我。 希望这会有所帮助。

答案 1 :(得分:1)

select正在获取对整个数组的引用,因此number属性不存在。尝试switchMap切换到扩展列表的新observable,这样就可以一次选择一个,如下所示:

const batStore$: Observable<BatStore> = this.store.select(fromBatStores.selectBatStoresBatStores)
    .switchMap((batStores : BatStore[]) => Observable.from(batStores))
    .single((bs: BatStore) => bs.number === editId);

答案 2 :(得分:0)

select方法将重新排列数组对象,因此您无法访问数字属性。您可以尝试以下方法:

ngOnInit() {
  const editId = 11;
  this.batStore$ = this.store.select(fromBatStores.selectBatStoresBatStores)
    .flatMap(list => list)// flat list to single elements, emit 1 value per element
    .single(bs => bs.number === editId);
}

另一种方法是将状态中的元素存储为键,值对,然后创建一个接受Id参数的选择器,或者将Id存储在状态中,然后组合2个选择器(1表示元素集合, 1对于Id)成为一个。