数组的RxJs BehaviorSubject允许设置/订阅各个项目

时间:2020-06-03 22:17:32

标签: javascript rxjs

我想使用BehaviorSubject存储对象数组,并有一种方法可以轻松更新(下一个)该数组的单个项目,而不必更新整个数组。

我还想以一种简单的方法来订阅对该数组的特定项的更改。我知道可以使用过滤器来完成,但是更简单的方法会很好...

有可能吗?

我目前正在使用自己创建的这个版本(我不知道这是否是最好的方法),该版本还将其内容持久保存到本地存储中:

export class LocalStorageBehaviorSubject<T, Y = T> {

  private _data: BehaviorSubject<T>;
  public asObservable() {
    return this._data.asObservable();
  }

  public next(data: T) {
    if(this.expirationFn !== null) {
      data = this.expirationFn(data);
    }

    localStorage.setItem(this.key, JSON.stringify(data));
    this._data.next(data);
  }

  public nextItem(item: Y) {
    if (!Array.isArray(this._data.getValue())) {
      throw "Type is not an Array";      
    }

    let dados: any = (<any>this._data.getValue()).slice();

    if (dados.some(r => r[this.id] === item[this.id])) {
      dados = dados.map(r => r[this.id] === item[this.id] ? item : r);
    } else {
      dados.push(item);
    }

    if(this.expirationFn !== null) {
      dados = this.expirationFn(dados);
    }

    localStorage.setItem(this.key, JSON.stringify(dados));
    this._data.next(<any>dados);
  }

  public removeItem(id) {
    if (!Array.isArray(this._data.getValue())) {
      throw "Type is not an Array";      
    }

    let dados: any = (<any>this._data.getValue()).slice();

    dados = dados.filter(r => r[this.id] !== id);

    localStorage.setItem(this.key, JSON.stringify(dados));
    this._data.next(<any>dados);
  }

  public removeExpiredData(){
    let data = this.loadFromStorage();

    if (data) {
      if(this.expirationFn !== null) {
        data = this.expirationFn(data);
      }

      this._data.next(data);
    }
  }

  public getValue() {
    this.removeExpiredData();

    return this._data.getValue();
  }

  public getItem(id): Y {
    if (!Array.isArray(this._data.getValue())) {
      throw "Type is not an Array";      
    }

    this.removeExpiredData();

    return (<any>this._data.getValue()).slice().find(t => t[this.id] == id);
  }

  constructor(private key: string, private id: string, defaultValue: any = null, private expirationFn: (dados: T) => T = null) {
    this._data = new BehaviorSubject<T>(defaultValue);

    this.removeExpiredData();
  }

  private loadFromStorage(): T {
    let dadosStr = localStorage.getItem(this.key);

    if (dadosStr) {
      return JSON.parse(dadosStr);
    }

    return null;
  }


}

我希望那是一种更简单的方法...

谢谢

1 个答案:

答案 0 :(得分:1)

我还想以一种简单的方法来订阅对 该数组的特定项目。我知道可以用滤镜来做,但是 一种更简单的方法会很好...

您可以在map array.find和lambda内部使用地图运算符

示例

const mockStorage = {
  values: {},
  setItem(key, value) {
    this.values[key] = value;
  },
  getItem(key) {
    return this.values[key]
  },
  clearItem(key) {
    this.values[key] = undefined;
  }
}

class LocalStorageBehaviorSubject {

  constructor(key, defaultValue) {
    this.key = key;
    this._data = new rxjs.BehaviorSubject(defaultValue);
  }

  nextItem(item) {
    const list = this._data.value;
    const itemIndex = list.findIndex(pr => pr.id === item.id);
  
    this._data.next([
      ...list.slice(0, itemIndex),
      {
        ...(list[itemIndex] || {}),
        ...item
      },
      ...list.slice(itemIndex + 1)
    ]);
  }

  removeItem(id) {
    this._data.next(this._data.value.filter(pr => pr.id !== id));
  }

  getItem(id) {
    return this.asObservable()
      .pipe(
        rxjs.operators.map(values => values.find(pr => pr.id === id) || null), 
        rxjs.operators.distinctUntilChanged());
  }

  asObservable() {
    return this._data.asObservable().pipe(
      rxjs.operators.tap(values => {
        if (values && values.length) {
          mockStorage.setItem(this.key, JSON.stringify(values));
        }
        else {
          mockStorage.clearItem(this.key);
        }
      }))
  }

}

const localStorageBehaviorSubject = new LocalStorageBehaviorSubject('items', []);

localStorageBehaviorSubject
  .getItem(1)
  .subscribe(item => {
    console.log(item);
  })
  
localStorageBehaviorSubject.nextItem({id: 1, value: 'test'})
localStorageBehaviorSubject.nextItem({id: 1, value: 'test1'})
localStorageBehaviorSubject.nextItem({id: 2, value: 'test2'})
localStorageBehaviorSubject.nextItem({id: 3, value: 'test3'})
localStorageBehaviorSubject.removeItem(2);
localStorageBehaviorSubject.removeItem(1);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>