问题描述
我使用BehaviorSubject
开发了一个自定义角度存储,并且使用的是这样:
export class UserFaceComponent {
@input()
public id: any;
public presence$: Observable<boolean>;
constructor(private _store: Store) { }
public ngOnInit() {
this.presence$ = this._store
.select(s => s.users.presences)
.pipe(
map(p => p.includes(this.id))
);
}
}
这样,当商店发生变化时,presence$
可观察对象将发出新值。它运作良好,但是传递给组件的id
也可能会更改。假设页面上有一个用户列表,当用户选择其中一个时,它会更新变量selectedUserId
,该变量将传递给UserFaceComponent
。该组件与以前相同,但是id
将被更新。
这意味着我必须在我的组件中创建一个主题,订阅onChange
钩子,并在id更改时在该主题上发出。然后,我必须将此可观察值与上面的一个合并,然后发出新值。
这可以工作,但是非常麻烦,我不想强迫使用这种方法制作的每个组件都这样做...我想了一段时间,但找不到其他解决方案解决这个问题...
解决方法
我多次遇到相同的要求,但是不幸的是,没有比您的onChange
-subject
方法更简单的解决方案了。我曾经读过有人建议使用ObservableInput
装饰器,但从未实现过。
除了您的方法外,还有另一种方法可以做到这一点,它并不是很简单,只是有所不同。这种替代方法使用输入getter和setter而不是ngOnChanges
生命周期钩子来更新主题。
private _id: BehaviorSubject<string> = new BehaviorSubject<string>();
@Input()
set id(value: string) {
this._id.next(value);
}
get id(): string {
return this._id.value;
}
,
如果您使用async
管道进行订阅,则可以为变量分配一个新的observable。 async
管道自动从其当前可观察对象退订,并且如果您为其输入分配了新的可观察对象,则订阅新的。
export class UserFaceComponent {
@Input()
public id: any;
public presence$: Observable<boolean>;
constructor(private _store: Store) { }
ngOnChanges(changes: SimpleChanges) {
if (changes['id']) {
const currentId = changes['id'].currentValue
this.presence$ = this._store
.select(s => s.users.presences)
.pipe(
map(p => p.includes(currentId))
);
}
}
}
<div>{{ presence$ | async }}</div>