如何获得仅在 redux 状态的对象数组中的属性值更改时才发出的 Observable?
Posted
技术标签:
【中文标题】如何获得仅在 redux 状态的对象数组中的属性值更改时才发出的 Observable?【英文标题】:How to get Observable that emits only when a property value changes in an array of objects in redux state? 【发布时间】:2021-10-14 07:44:20 【问题描述】:我在 Angular 应用中有 redux 状态:
export interface UIAction
name: string;
isActive: boolean;
export interface IUIState
actions: UIAction[];
我已经构建了一个 Angular 服务,它订阅状态并将每个操作的主题存储在 Map 中,并为对某个操作的 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 ]
但订阅不会写入控制台,因为它没有订阅“取消”操作的更改。
然后我发送另一个 redux 状态更改(这里只有值):
name: 'Save', isActive: true
UIState.actions 变为:
[ name: 'Save', isActive: true, name: 'Cancel', isActive: false ]
现在订阅写入控制台:
Value: true
因为它订阅了“保存”操作的更改。
【问题讨论】:
或许distinctUntilChanged
运营商可以帮到你
我自己发现了它并认为我明白了
由于您正在处理对象,distinctUntilChanged()
将不起作用,因为每个对象引用都是唯一的。使用distinctUntilKeyChanged('isActive)
,因为它将运行此特定对象属性的条件。
我故意写了distinctUntilChanged
,因为你可以指定一个比较函数,我不认为distinctUntilKeyChanged
会帮助他,因为它是一个对象数组
【参考方案1】:
希望我正确理解了这个要求。对于更复杂的情况,您可以将自定义函数应用到 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()
返回undefined
应用一个自定义函数来检查name
和isActive
。如果任一属性与其先前的值不匹配,它将发出新值。
现在我们有了新值,返回 isActive
布尔值。
【讨论】:
感谢您的回答,但包含项目的数组称为操作。因此必须从 uiState.actions 中搜索有问题的项目。这在“注释代码”中说。 我更新了我的问题以更好地解释我需要什么【参考方案2】:如果有人对此感兴趣,我会这样做。感谢其他人指出我正确的方向:
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));
【讨论】:
以上是关于如何获得仅在 redux 状态的对象数组中的属性值更改时才发出的 Observable?的主要内容,如果未能解决你的问题,请参考以下文章