Managing rxjs subscriptions with takeUntil()

Nick Raphael - Nov 5 '19 - - Dev Community

Whenever posible we should resist the temptation to subscibe to our observables. If we want to acccess the observable values in our template, it is better to use the async pipe. The async pipe will handle the subscription lifecycle for us. We simple don't have to worry about unsubscribing.

But in those situations where we must subscribe to an observable in our component, we need to handle the unsubscribe ourselves.

The traditional way of unsubscribing is the keep a reference to the subcription and call unsubscibe in ngOnDestroy...

export class MyComponent implements OnInit, OnDestroy {

  private numbersSubscription: ISubscription;
  private lettersSubscription: ISubscription;

  ngOnInit() {
    this.numbersSubscription= of([1, 2, 3]).subscribe(numbers => {});
  }

  someMethodCalledLater() {
    this.lettersSubscription= of(['a', 'b', 'c']).subscribe(letters => {});
  }

  ngOnDestroy() {
    this.numbersSubscription.unsubscribe();
    if(this.lettersSubscription) {
      this.lettersSubscription.unsubscribe();
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

I've used this pattern many times but found that it gets unwieldy when you have a number of subscriptions. A better pattern is to use the takeUntil operator. Lets refactor the same situation...

export class MyComponent implements OnInit, OnDestroy {

  private onDestroy = new Subject();

  ngOnInit() {
    this.numbersSubscription= of([1, 2, 3])
      .takeUntil(this.onDestroy)
      .subscribe(numbers => {});
  }

  someMethodCalledLater() {
    this.lettersSubscription= of(['a', 'b', 'c'])
      .takeUntil(this.onDestroy)
      .subscribe(letters => {});
  }

  ngOnDestroy() {
    this.onDestroy.next();
    this.onDestroy.unsubscribe();
  }
}
Enter fullscreen mode Exit fullscreen mode

This looks simpler to my eyes. We can add any number of subscriptions and all we need to do is add .takeUntil(this.onDestroy) to each call.

. . . . . . . . . . . . . . . . . . . . . . . . . .