1
votes

If I am ever working with rxjs, I normally, in my component file, keep track of all of my subscriptions by pushing said subscriptions into a Subscription array:

private subcriptions: Subscription[];

this.subscriptions.push(this.myObservableOne.subscribe(...));
this.subscriptions.push(this.myObservableTwo.subscribe(...));

public ngOnDestroy(): void {
    this.subscriptions.forEach(s => s.unsubscribe());
}

Now, I am running into something that I thought was interesting. If I instead need to subscribe to an Observable from a service:

this.myService.myObservable.subscribe(...)

Who owns the subscription? Will my component own it, or will the service own it? In other words, will my service need to implement ngOnDestroy to unsubscribe from that Observable?

I feel like doing: this.subscriptions.push(this.myService.myObservable.subscribe(...)); might work but I am not entirely sure.

2

2 Answers

2
votes

Calling .subscribe(...) on an Observable returns a Subscription.

If you don't assign this subscription to a variable (or in your case push it to an array of subscriptions), you will lose reference to this subscription, hence you can't unsubscribe from it, which can cause memory leaks.

So your assumption of pushing it into array of subscriptions:

this.subscriptions.push(this.myService.myObservable.subscribe(...));

and unsubscribing in ngOnDestroy of your component is correct.

1
votes

Another option is to use takeWhile or something similar with a flag such as the componentActive flag below. Something like the code shown below.

This completes the subscription so you don't need to unsubscribe.

import { Component, OnInit, OnDestroy } from '@angular/core';

import { Product } from '../product';

import { Observable } from 'rxjs';
import { takeWhile } from 'rxjs/operators';

/* NgRx */
import { Store, select } from '@ngrx/store';

@Component({
  selector: 'pm-product-list',
  templateUrl: './product-list.component.html',
  styleUrls: ['./product-list.component.css']
})
export class ProductListComponent implements OnInit, OnDestroy {
  componentActive = true;

  // Used to highlight the selected product in the list
  selectedProduct: Product | null;

  constructor(private store: Store<fromProduct.State>) { }

  ngOnInit(): void {

    // Subscribe here because it does not use an async pipe
    this.store.pipe(
      select(fromProduct.getCurrentProduct),
      takeWhile(() => this.componentActive)
    ).subscribe(
      currentProduct => this.selectedProduct = currentProduct
    );

  }

  ngOnDestroy(): void {
    this.componentActive = false;
  }

}