The BehaviorSubject Explained

BehaviorSubject is a specialized form of a Subject that maintains a concept of the present value it holds and delivers to each new subscription. This present value is either the latest item emitted from the source, or a fallback default if nothing has been emitted to that point. A BehaviorSubject must be initialized with a starting value, since there is always a requirement for a current item. When you need the most recent emitted value(s) upon subscription but don't want to supply a starting default, consider using a ReplaySubject instead.

Because of this characteristic, you can always retrieve the most recent value from the BehaviorSubject directly, regardless of how much time has passed since the value was produced. When an observer subscribes, the subject first pushes the current value, then any subsequent items from the source Observable(s) are forwarded. One key distinction from the ReplaySubject: if the BehaviorSubject enters a terminal state, it will only deliver a COMPLETE or ERROR signal. In contrast, a ReplaySubject in a terminal state will still playback its cached items before sending out the COMPLETE or ERROR signal. A subject typically transitions to this terminal state when its source observable completes or fails.

When the source observable encounters an error, the BehaviorSubject will not relay any items to future subscribers. Instead, it only forwards the error notification from the source to any new subscribers.

The internal workings of BehaviorSubject can be outlined as follows:

  1. Initialize a container for managing subscriptions
  2. Set the retained current value to the initial value supplied at creation time
  3. When a new subscription is established, add it to the container and send the current value to that specific observer
  4. When the source emits a value or the next method is invoked, refresh the current value with the newly received item and broadcast it to all observers
  5. Upon source completion or when the complete method is called, mark the subject as stopped and store the completion notification as the current value; send that notification to all existing subscriptions and clear them from the container
  6. If the source throws an error or the error method is invoked, mark the subject as stopped and store the error notification as the current value; deliver the error notification to all current subscriptions and remove them
  7. When the subject is stopped, refuse new subscriptions to the container, and instead instantly send the current stored notification (either complete or error) to the new observer
  8. If a stopped subject is paired with a fresh source observable, ignore any emissions from that new source

Typical Applications

BehaviorSubject – RxJS Reference — figure 1

The BehaviorSubject is frequently employed as a store or cache that lets subscribers pull the most recent value on demand. The following example shows a straightforward representation of such a store:

const state1 = {name: 'James', age: 33};
const state2 = {name: 'Anna', age: 27};

const store = new BehaviorSubject(state1);

const v1 = getValueFromStore();
console.log(v1.name); // 'James'

updateStore(state2);

const v2 = getValueFromStore();
console.log(v2.name); // 'Anna'

selectFromStore((state) => state.age).subscribe((v) => console.log(v));

function updateStore(v) {
   store.next(v);
}

function getValueFromStore() {
   return store.value;
}

function selectFromStore(selector) {
   return store.asObservable().pipe(
       map(selector)
   );
}

Interactive Example

Further Reading