DEV Community

diptee
diptee

Posted on • Edited on

Angular : RxJS BehaviorSubject

As we know multiple components share the common data and always need updated shared data. In such scenarios most of the time BehaviorSubject is used which acts as a single store to hold updated shared data.

  • BehaviorSubject is both observer and type of observable.
  • BehaviorSubject always need an initial/default value.
  • Every observer on subscribe gets current value.
  • Current value is either latest value emitted by source observable using next() method or initial/default value.

Let’s implement BehaviorSubject to understand a concept better!

For e.g In order tracking app, display total items in cart and total items in wish list on UI in header and dashboard section based on user action.

Now we have three components -
HeaderComponent, DashBoardComponent, TableComponent

UI
Run Live

When user add items in the cart/wishList, total count needs to be updated in the header and dashboard component.

1.First create a BehaviorSubject in order service which holds the initial state of order count ,so that it can be used by any component.
service
2.Now all observers(3 components) need to subscribe to source observable to get current value and show it on UI.
header
dashboard
table

3.When a user performs any action, call the next() method of BehaviorSubject. When the next() method gets called it will update current count with new count and notifies updated count to all observers(3 Components) who subscribed to source observable.

Action

This way BehaviorSubject makes components communication more effective.

P.S. Don't forget to unsubscribe all subscriptions in ngOnDestroy() to avoid memory leaks & unexpected output.

Thanks for reading! If you found this helpful please share!

Top comments (13)

Collapse
 
stradivario profile image
Kristiqn Tachev • Edited

Everything is awesome but there is one thing you should pay attention.

By subscribing inside ngOnInit you are introducing a memory leak since this hook will be triggered on component initialization.

For example going to page / and then /orders for example. Go back and forward a few times and print out console.log inside the subscription. You should get a multiple console log printing instead of one. This is because you are not unsubscribing from the observable.

One way to mitigate this issue is by letting html template to subscribe for you using async pipe

<div>{{ orderCount | async }}</div>
Enter fullscreen mode Exit fullscreen mode

Inside the ngOnInit you just need to define the observable

ngOnInit(){
  this.orderCount = this.orderService.getOrderCount();
}
Enter fullscreen mode Exit fullscreen mode

In some cases when you need to subscribe for example to router change event you don't need to subscribe inside the template so you can use a different approach

import { Subscription } from 'rxjs';
class MyComponent {
 subscription: Subscription;
 ngOnInit() {
  this.subscription = this.orderService.getOrderCount().subscribe();
 }

 ngOnDestroy() {
  if (this.subscription) {
   this.subscription.unsubscribe();
  }
 }

}

Enter fullscreen mode Exit fullscreen mode

Cheers!

Collapse
 
kforp profile image
George Koval.

You maybe interested to unsubscribe using takeUntil instead of saving the subscription and manually unsubscribing (you can have multiple subscriptions and it's not that convenient to manually unsubscribe from all of them).

Collapse
 
ahelmi365 profile image
Ali Helmi

Can you please post an article explaining how to use "TakeUntil" to unsubscribe all subscriptions?

Collapse
 
dipteekhd profile image
diptee

Thanks for mentioning this point!
Yes it is necessary to unsubscribe Subject, BehaviorSubject subscriptions in ngOnDestroy() to avoid memory leaks & unexpected output.

Collapse
 
sekharkumar profile image
sekhar

Fantastic blog

Collapse
 
ahelmi365 profile image
Ali Helmi

Can you please post an article explaining how to use "TakeUntil" to unsubscribe all subscriptions?

Collapse
 
stradivario profile image
Kristiqn Tachev

Here you go mate :)

import { Subscription } from 'rxjs';

class MyComponent {

 destroy$ = new Subject();

 ngOnInit() {
   this.orderService.getOrderCount().pipe(takeUntil(this.destroy$)).subscribe();
 }

 ngOnDestroy() {
  this.destroy$.complete();
 }
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
shubham1629 profile image
shubham1629

Fantastic blog !!! Short and informative

Collapse
 
dipteekhd profile image
diptee

Thank u ...

Collapse
 
siddev profile image
Siddhant Jaiswal

Nice!!! its helpful

Collapse
 
dipteekhd profile image
diptee

Thank u ...

Collapse
 
ankita_tripathi_5cdae815b profile image
Ankita Tripathi

Amazing one Diptee! Why don't you submit this to Google's Dev Library as well? devlibrary.withgoogle.com/

Collapse
 
dipteekhd profile image
Info Comment hidden by post author - thread only accessible via permalink
diptee

Thanks ankita.Sure will submit!

Some comments have been hidden by the post's author - find out more