8

since it's well known that use getValue() method on a BehaviorSubject should be avoided link I'm wondering what's the best way to read and updated a BehaviorSubject.

In my case I've a BehaviorSubject storing an array of objects and when I click on a button I should push another object to the array and emit the new value to all the subscribers.

Right now I'm doing:

this.myBehaviorSubject.next([
    ...this.myBehaviorSubject.value,
    { new object }
])

Is there a better approach?

Thanks!!

user2010955
  • 3,871
  • 7
  • 34
  • 53
  • It looks like you should better use the `scan` operator with `share` for this. – martin Jul 23 '18 at 08:28
  • @user2010955 yes, if you don't understand what you're doing, you should avoid `getValue`. But, it is a core method of BhaviorSubject, and it's very useful. I put some detail in my answer. – madjaoue Jul 23 '18 at 09:35

1 Answers1

2

Imperative is not good or bad, it depends on how you use it.

Publish

use next method. Here's what it looks under the hood :

// update this._value and call Subject's next method 
next(value: T): void {
    super.next(this._value = value);
}

// Subject's next method
next(value?: T) {
    if (this.closed) {
      throw new ObjectUnsubscribedError();
    }
    if (!this.isStopped) {
      const { observers } = this;
      const len = observers.length;
      const copy = observers.slice();
      for (let i = 0; i < len; i++) {
        copy[i].next(value);
      }
    }
}

It's difficult to be more straightforward if you want to update the current value and send it to observers.

Get the current Value

The natural way to get values from any Observable is to subscribe to it. In most cases, getValue is really a bad idea because, in most cases, Observables are chained, used asynchronously. For example, if you want to merge or zip the values of two subscribers, the way to go is :

zip(Subject_1, myBehaviorSubject).subscribe( val=> console.log(val));

Now, in some cases, you just need to access the current value, synchronously, and without chaining operators. In this case, use getValue. Under the hood :

getValue(): T {
    if (this.hasError) {
      throw this.thrownError;
    } else if (this.closed) {
      throw new ObjectUnsubscribedError();
    } else {
      return this._value;
    }
}
madjaoue
  • 5,104
  • 2
  • 19
  • 31
  • How would you modify a property of the subject's currentValue? Should I subscribe to it, modify and then use next() ? – btx Nov 08 '18 at 22:48
  • 1
    @btx The wrong way is to update `BSubject._value = newValue`. Please don't do this, it will you give you a headache sooner than later. What you described would be the right way to do it. So to recap, the good way is to get the current value, update it and push it again. To get the current value : `getValue` (synchronous) or `subscribe` (asynchrounous). push it using `next(newValue)`. Keep in mind that this will emit the new value to all subscribers. – madjaoue Nov 09 '18 at 12:10