Angular — Manage your unsubscription with the class inheritance feature

RxJS is a common library in the world of Angular. If you have been using RxJS for some time, you may have already faced the unsubscription issue. In simple, after making a subscription in Angular, you will need to manually unsubscribe it most of the cases at a certain point to avoid memory issues. One of the most common ways is to unsubscribe when the component is destroyed:

export class TestComponent implements OnDestroy {
subscription;
constructor(
private testService: TestService
) {
this.subscription = testService.testObservable
.subscribe(val => {
console.log(val);
})
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}

The Problem

In fact, the code above works totally fine, except it is very crunky. What we really care is only the code inside the subscription, where the business logic is happening at. Yet, in order to manage the unsubscription, we have to make an extra variable to store the subscription and some extra logic to unsubscribe it when the component is destroyed. There is lots of redundant codes and distractions. Besides, another issue here is that it is not declarative. When we look into the subscription itself, we don’t know when it will be unsubscribed. It will become very difficult to manage when your component grows large and starts to have dozen of subscriptions.

export class TestComponent implements OnDestroy {
subscriptionA;
subscriptionB;
subscriptionC;
subscriptionD;
subscriptionE;
... ngOnDestroy() {
this.subscriptionA.unsubscribe();
this.subscriptionB.unsubscribe();
this.subscriptionC.unsubscribe();
this.subscriptionD.unsubscribe();
this.subscriptionE.unsubscribe();
}
}

All these codes are meaningless to your business logic!

Unsubscribe in a Declarative Approach

The first improvement we can do is to make it declarative. Instead of making variables to store subscriptions, we add a subject to notify the destruction of the component. As a result, we can declare the life time of our subscriptions at the moment when we create them.

export class TestComponent implements OnDestroy {
destroyed = new Subject();
constructor(
private testService: TestService
) {
testService.observableA
.pipe(takeUntil(this.destroyed))
.subscribe(val => {
console.log(val);
})
testService.observableB
.pipe(takeUntil(this.destroyed))
.subscribe(val => {
console.log(val);
})
...
}
ngOnDestroy() {
this.destroyed.next();
this.destroyed.complete();
}
}

Now we know when the subscriptions will be unsubscribed by simply looking into the subscriptions themselves. Besides, multiple subscriptions can share the same destruction subject, which helps to reduce redundant code.

Manage Your Subject with a Base Component

In order to make it even cleaner, we can make a base component to handle the destruction subject.

export class BaseComponent implements OnDestroy {
destroyed = new Subject();
constructor() {}
ngOnDestroy() {
this.destroyed.next();
this.destroyed.complete();
}
}
export class TestComponent extends BaseComponent {
constructor(
private testService: TestService
) {
super();
testService.observableA
.pipe(takeUntil(this.destroyed))
.subscribe(val => {
console.log(val);
})
testService.observableB
.pipe(takeUntil(this.destroyed))
.subscribe(val => {
console.log(val);
})
...
}
}

That’s all! Now only what we care are left inside our components!

Thanks for reading! Any comments would be highly appreciated. :D

Web developer from Hong Kong. Most interested in Angular and Vue. Currently working on a Nuxt.js + NestJS project.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store