DEV Community

Cover image for Managing rxjs subscriptions with takeUntil()
Nick Raphael
Nick Raphael

Posted on • Updated on

Managing rxjs subscriptions with takeUntil()

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.

Discussion (1)

Collapse
j3nnning profile image
Jenning Ho • Edited on

this.onDestroy.unsubcribe() is unecessary since it is only used in takeUntil.

takeUntil have an internal unsubscribe.

there's also no need to do a .complete() call like some does.
a single .next() is enough
you can read more about it here

twitter.com/Michael_Hladky/status/...
twitter.com/kreuzercode/status/123...