我仍然试图围绕rxjs和observables以及BehaviorSubject。我想要做的是,结合BehaviorSubject和LocalStorage,以便在特定的LocalStorage变量发生变化时通知所有组件。
例如,请考虑以下方案。
Component1和Component2有两个组件。
这两个组件都在LocalStorage中查找名为Component1和Component2的变量,它包含一种颜色,并显示该颜色的正方形。
Component1需要在LocalStorage中订阅“Component1Color”键,而Component2需要在LocalStorage中订阅“Component2Color”。
执行此操作的一种方法是使用BehaviorSubject维护LocalStorage的状态,并且只要对任何变量进行更改,就会将此消息广播到已订阅BehaviorSubject的所有组件。
这种方法的问题在于,当Component2Color更新时,component1也会得到通知,并且不会对它做任何事情。
什么是好的,只有当Component1Color更新时,Component1才会得到通知,而只有在更新Component2Color时才会通知Component2。有没有办法可以使用一个BehaviorSubject来完成?
答案 0 :(得分:2)
您可以通过StorageEvent
const storage = Rx.Observable.fromEvent(window, 'storage').groupBy(ev => ev.key);
然后您可以通过执行以下操作来访问每个流:
let component1Stream = storage.filter(x => x.key === 'Component1Color').merge();
//Or using flatMap
let component2Stream = storage.flatMap(x =>
x.key === 'Component2Color' ? x : Rx.Observable.empty()
);
修改强>
正如评论中指出的那样,存储事件仅对跨页面更新有用,如果您在同一页面上,它将不会更新。幸运的是,解决方案几乎完全相同,您只需要为localStorage对象提供一个装饰器对象,以便它可以发出事件。
class RxLocalStorage {
private _subject: Rx.Subject<any>;
private _updates: Observable<any>;
constructor() {
this._subject = new Rx.Subject();
this._updates = this._subject.groupBy(ev => ev.key)
.share();
}
getItem(key) { return this._updates.filter(x => x.key === key).merge(); }
setItem(key, newValue) {
const oldValue = localStorage.getItem(key);
const event = {key, newValue, oldValue};
localStorage.setItem(newValue);
this._subject.next(event);
}
}
let myLocalStorage = new RxLocalStorage();
myLocalStorage.getItem('Component1Color')
.subscribe(x => console.log('Component1 Color changed'));
myLocalStorage.setItem('Component1Color', 'blue');
//-> Component1 Color changed
请注意,上述内容假设您在开始进行更改之前已完成所有订阅。