如何获得仅当 属性 值在 redux 状态的对象数组中发生变化时才发出的 Observable?

How to get Observable that emits only when a property value changes in an array of objects in redux state?

我在 angular 应用程序中有 redux 状态:

export interface UIAction {
  name: string;
  isActive: boolean;
}
    
export interface IUIState {
  actions: UIAction[];
}

我构建了一个 angular 服务,该服务订阅状态并在 Map 中存储每个操作的主题,returns 该主题供对特定操作的 isActive-value 感兴趣的调用者使用.是这样的:

public getIsActive$(name: string): Observable<boolean> {  
  let sub = this.subsMap.get(name);
  return sub.asObservable();
}

现在我想更改代码并删除包含所有主题的地图并执行如下操作:

public getIsActive$(name: string): Observable<boolean> {  
  return this.ngRedux.select<IUIState>('ui').pipe(
  /* this should use some operators so that
     the returned Observable emits only when 
     UIAction.isActive changes for the action 
     in question. The action in question is
     found from the state.actions-array using 
     parameter 'name' */
   )));
}

这应该怎么做?下面举个例子。

最初 UIState.actions 看起来像这样:

[ { name: 'Save', isActive: false }, { name: 'Cancel', isActive: true } ]

此时我调用

myService.getIsActive$('Save').subscribe(isActive => {
  console.log('Value : ${isActive});
});

然后我发送一个 redux 状态更改(这里只有新值):

{ name: 'Cancel', isActive: false }

UIState.actions 更改为:

[ { name: 'Save', isActive: false }, { name: 'Cancel', isActive: false} ]

但是订阅不会写入控制台,因为它没有订阅 'Cancel' 操作的更改。

然后我发送另一个 redux 状态更改(这里只有值):

{ name: 'Save', isActive: true }

并且 UIState.actions 更改为:

[ { name: 'Save', isActive: true}, { name: 'Cancel', isActive: false} ]

现在订阅写入控制台:

Value: true

因为它订阅了 'Save' 操作的更改。

希望我正确理解了这个要求。对于更复杂的情况,您可以将自定义函数应用于 distinctUntilChanged()

public getIsActive$(name: string):Observable<boolean> {
  return this.ngRedux.select<IUIState>('ui').pipe(
    map(uiState=>uiState.find(state=>state.name===name)),
    filter(state=>!!state),
    distinctUntilChanged((prev, curr)=>
      prev.name===curr.name && prev.isActive === curr.isActive
    ),
    map(state=>state.isActive)
  );
}

这里逐行说明发生了什么:

  • 根据名称查找数组中的状态
  • 过滤掉以防 .find() returns undefined
  • 应用检查 nameisActive 的自定义函数。如果 属性 与其先前的值不匹配,它将发出新值。
  • 现在我们有了新值,return isActive 布尔值。

如果有人对此感兴趣,我就是这样做的。感谢其他人为我指出正确的方向:

public getIsActive$(name: UIActionName): Observable<boolean> {
  return this.getUIAction$(name).pipe(
    map(axn => axn.isActive)).pipe(distinctUntilChanged());
}

private getUIAction$(name: UIActionName): Observable<UIAction> {
  return this.ngRedux.select<IUIState>('ui').pipe(map(state => {
    return state.actions.find(actn => actn.name === name);
  })).pipe(
    filter((axn: UIAction | undefined): axn is UIAction => axn !== undefined));
}