BehaviorSubject 和本地存储

BehaviorSubject and Local Storage

我仍在努力思考 rxjs 和 observables 以及 BehaviorSubject。我想做的是,结合 BehaviorSubject 和 LocalStorage,以便在特定 LocalStorage 变量更改时通知所有组件。

例如,考虑以下场景。

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

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

这种方法的问题在于,当更新 Component2Color 时,component1 也会收到通知,但不会对此做任何处理。

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

您可以通过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

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