Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why to use BehaviorSubject in shared service and not use simple shared variables?

I'm a little confused about the use of BehiavorSubject instead of using shared variables in a service. If I create a service with shared variables and even overwrite them, the angular components also detect these changes, then why should I use BehiavorSubject instead of shared variables? for example in my project I have a navigation bar that is displayed if the user is logged in so I have ngIf service.isLoggedIn and it works fine. why do I need an observable in service and subscribe to its events. If someone changes this value from a different component it will change here as well. I am new to angular let me know if I am missing something. Thank you (I am following this example: https://loiane.com/2017/08/angular-hide-navbar-login-page/)

like image 1000
rivka Avatar asked Dec 17 '22 12:12

rivka


2 Answers

Yes, you said it right that shared variables can be used which, in turn, can detect the changes and update the view accordingly !

Then why do we need Subject or BehaviorSubject ?

The simple answer is,

when it is only about changing the view directly as per updated shared variable something like below,

 <div>Result : {{sharedService.result}}</div>

using shared variable makes sense. So, in shared service, you just change result to 10 and immediately view will be updated with 10 value.

But

what when result is 10, in (any) component, you want to run some piece of code/logic ???
How can you make sure that when result gets 10 value, some logic will be run (in the component ?)

something like below,

some.component.ts

       if(sharedService.result === 10){  

             // This code can not run with shared variable approach

       }

Q: Can we write something like above in component ?
A: yes

Q: After writing it, will it run the logic written inside?
A: No

Q: Why ?
A: Because, shared variables are (using service) referenced type. It means whenever you change the value, all references will be changed (for singleton service) in your application but code written in some.component.ts won't run or trigger.

Q: Why ?
A: Because in javascript/angular, to execute such type of scenario/code, you should have a mechanism of callback.

Q: What is callback ?
A: A function which can be passed as a parameter to any function which has ability to execute itself once the main function is executed.

That's the basic knowledge required to understand BehaviourSubject.

Now when you define a behaviourSubject in the service as below,

Shared.Service.ts

    myBehaviorSubject = new BehaviourSubject(); // has ability to register a callback function     

You can use myBehaviorSubject in any component as below,

some.component.ts

    constructor(private sharedService:SharedService){

        // below subscribe line registers a callback function with myBehaviorSubject.

        this.sharedService.myBehavioirSubject.Subscribe((value)=>{     // This is callback function `(value)=>{...}` 

            if(value === 10){   // When value gets 10 value, below code will run automatically

                // This code will run when condition is met

            }
        })
    }

Now, behaviourSubject has some extra mechanism to emit the value. So if I emit 10 value from anywhere like this.myBehaviourSubject.next(10), due to internal mechanism of behaviourSubject, registered callback function will be called. As it is a function, when 10 value is emitted, a callback function will execture itself and it will run other logic written inside the function.

I hope, with this understanding you will be able to understand why shared variables are different from behaviourSubject

like image 125
Nikhil Shah Avatar answered Mar 30 '23 00:03

Nikhil Shah


That's a fair question. And based on your comment, keeping it as a variable might be the best and simplest solution. Here are a few use-cases, though, that I can think of:

  • To perform logic every time the value changes. You could also do this in set function on your variable, but using RxJS gives you easy access powerful operators such as debounce and several mapping operators. Need to make an API call every time the value changes, but you want to wait until the user is done typing before hitting your API? RxJS is a fantastic solution to that.

  • You can combine it with other observables. Maybe you have another stream of events. Making that variable an Observable, you can easily plug changes to the variable into that other stream.

  • Better Angular performance. By using a BehaviorSubject (which is a type of observable), you can put a reference to it inside of the Angular template and use the async pipe to automatically subscribe and automatically mark it for change detection when the value changes. So it would look like this: service.isLoggedIn | async. If you do your whole component this way, you could eventually switch the ChangeDetectionStrategy to OnPush, which is far more performant. Or even better, you could switch to the ngrxPush pipe and move your application entirely out of Angular zones, improving performance even more.

Just remember that even though your changes "magically" update in the components, that magic comes at a cost. Angular had to figure out what changed, and don't think it figured that out on the first go. It's constantly monitoring your application-- every button click, every input, sometimes even hover events will trigger change detection. So the more you can provide hooks into what changed, and when it changed, you've made it that much easier to improve performance.

like image 21
Jesse Avatar answered Mar 30 '23 00:03

Jesse