Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Observable vs Subscription when using Subject values

Tags:

angular

rxjs

I'm quite new to Angular and from what I can tell Subject is the standard class used for multicasting. When trying out this class I've found that there are two (probably even more) avenues of dealing with changes in its value.

  1. Using Observable type objects within the component directly

    In this approach an Observable is declared within the component like so:

    foo$ : Observable<boolean>;
    

    and is then used in the html file using the following method:

    <p *ngIf="(foo$ | async) as foo">Bar!</p>
    
  2. The second approach is to have a Subscription type object within the component which assigns to some member variable:

    s: Subscription;
    foo: boolean;
    

    Where the subscription is initialized as follows:

    constructor(private fbs: FooBarService) {
        this.s = fbs.fooObservable.subscribe(v => this.foo = v);
        //  this.s.unsubscribe() is called within ngOnDestroy()
    }
    

    The html would then use the code like this:

    <p *ngIf="foo">Bar!</p>
    

Is there any reason, other than personal preference, to prefer either one of these approaches?

like image 862
abcalphabet Avatar asked Oct 25 '25 08:10

abcalphabet


1 Answers

Is there any reason, other than personal preference, to prefer either one of these approaches?

These kinds of questions are off topic here, but there is value to the community in giving a general answer. There is enough distinction between the two that it should be talked about.

One approach is called a reactive component and the other is a stateful component.

Reactive Components

The view handles presentation of data from observables using the async pipe. If a component only uses observables and async pipe for presentation, then the component is stateless and reacts to changes automatically via the view. This helps create a drier feel for the templates.

This approach has the following advantages.

  • Less likely to get the "Expression has changed after it was checked" error.
  • Easier to represent the external state of a service or storage via observables.
  • Makes use of OnPush change notification a lot easier.
  • This approach by design creates a more responsive component that reactives to changes with far less effort on the part of the developer.

This approach has the following disadvantages.

  • Developers are likely to write data.subscribe(value => this.value = value) when they don't understand reactive programming.
  • Source code can be difficult to understand when multiple observables are merged, switched or combined without much explanation as to why.
  • Introduces the risk for memory leaks and lost subscriptions.
  • Developers can sometimes use operators where they don't understand all of the side effects. Using mergeMap() instead of switchMap() as an example.
  • You have to track the life cycle of observables.
  • IDE editors have a harder time autocompleting the types. For example; <ng-container *ngIf="data$ | async as data"> will create a view variable data that is of an unknown type in most IDEs.
  • A steep learning curve. RXJS is not easy to master.
  • It is difficult to debug with debugger; because the component has no state to debug.
  • It is harder to unit test. There is no component state to assert that it is correct.

Stateful Components

A component is stateful when it has properties that are used in the view template. The internal state of the component must be changed in order to represent a change in the view, and this is the default type of component in Angular.

This approach has the following advantages.

  • It is easier to develop, maintain and read the source code.
  • @Input() bindings are stateful to begin with.
  • IDEs have better autocomplete features for component properties.
  • Has an easier learning curve. No need to learn a third-party library.
  • It is easier to use debugger; in the browser, because you can see the current state of the component.
  • It is easier to unit test.

This approach has the following disadvantages.

  • Most likely to get the "Expression has changed after it was checked" error when using external states from services.
  • Source code becomes cluttered with subscribe() calls when you mix in observables.
  • You have to manually convert reactive streams into component state, and write code like data.subscribe(value => this.data = value).
  • Change detection becomes a challenge when using external observables.
  • It takes more lines of code to create a responsive component that reactives to external events and observables.

Conclusion

When deciding which of the two approaches to use. I recommend starting with stateful components but progress your skills towards the reactive components.

From my experience, reactive components are the way to go because they are destinations for observable streams. These are components that bring together observables to create a responsive view of that data, and they react automatically to changes in those streams. At the sametime, merging of data as a destination is more of an architectural design in Angular. So it's a broader discussion and topic, but keep learning and you'll get there.

like image 152
Reactgular Avatar answered Oct 27 '25 00:10

Reactgular