2

我仍在尝试围绕 rxjs 和 observables 和 BehaviorSubject 进行思考。我想做的是,将 BehaviorSubject 和 LocalStorage 结合起来,以便在特定 LocalStorage 变量发生变化时通知所有组件。

例如,考虑以下场景。

  • 有两个组件 Component1 和 Component2。

  • 这两个组件都在 LocalStorage 中查找名为 Component1 和 Component2 的变量,它们包含一种颜色,并且它们显示该颜色的正方形。

Component1 需要订阅LocalStorage 中的“Component1Color”键,Component2 需要订阅LocalStorage 中的“Component2Color”。

一种方法是使用 BehaviorSubject 来维护 LocalStorage 的状态,并且在任何时候对任何变量进行更改时,都会将此消息广播到已订阅 BehaviorSubject 的所有组件。

这种方法的问题在于,当 Component2Color 更新时,component1 也会收到通知,并且不会对此采取任何措施。

更好的是,Component1 仅在 Component1Color 更新时收到通知,而 Component2 仅在 Component2Color 更新时收到通知。有没有一种方法可以使用单个 BehaviorSubject 来完成?

4

1 回答 1

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

请注意,以上假设您的所有订阅都是您开始进行更改之前完成的。

于 2016-07-08T19:26:54.157 回答