23
loading...
This website collects cookies to deliver better user experience
async
pipe, but the article is not about it. It's about situations where you need to subscribe inside component's ts
file and how to deal with it. This article is about dealing with repetitive logic of cancelling subscription in different components.async
pipe. The rule of thumb is if you subscribe, you should always unsubscribe. Indeed, there are finite observables which autocomplete, but those are separate cases.Observable
;rxjs
and Angular features.npx
since I don't install any packages globally.npx @angular/cli new ng-super-easy-unsubscribe && cd ng-super-easy-unsubscribe
Observable
and a component that will subscribe to it, perform some memory consuming operation in subscribe function and never unsubscribe.npx @angular/cli generate component careless
npx @angular/cli generate service services/interval/interval
interval
there:// src/app/services/interval/interval.service.ts
import { Injectable } from '@angular/core';
import { interval, Observable } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class IntervalService {
public get getInterval(): Observable<number> {
return interval(250);
}
}
CarelessComponent
on and off, with mere 4 lines of template we can put it directly in the ts
file:// src/app/app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<section>
<button (click)="toggleChild()">toggle child</button>
</section>
<app-careless *ngIf="isChildVisible"></app-careless>
`,
styleUrls: ['./app.component.css'],
})
export class AppComponent {
public isChildVisible = false;
public toggleChild(): void {
this.isChildVisible = !this.isChildVisible;
}
}
Observable
emission.// src/app/careless/careless.component.ts
import { Component, OnInit } from '@angular/core';
import { IntervalService } from '../services/interval/interval.service';
import { UnsubscribeService } from '../services/unsubscribe/unsubscribe.service';
@Component({
selector: 'app-careless',
template: `<p>ಠ_ಠ</p>`,
})
export class CarelessComponent implements OnInit {
private garbage: string[][] = [];
public constructor(private intervalService: IntervalService) {}
public ngOnInit(): void {
this.intervalService.getInterval.subscribe(async () => {
this.garbage.push(Array(5000).fill("some trash"));
});
}
}
CarelessComponent
instance comes to life.rxjs
operator that unsubscribes once the component is destroyed.providedIn
property in the @Injectable
decorator, we can provide the service on component level, which allows us to access OnDestroy
hook in the service. And this is how we will know component is being destroyed, because the service will be destroyed too.npx @angular/cli generate service services/unsubscribe/unsubscribe
Subject
and takeUntil
operator:import { Injectable, OnDestroy } from '@angular/core';
import { Observable, Subject, takeUntil } from 'rxjs';
@Injectable()
export class UnsubscriberService implements OnDestroy {
private destroy$: Subject<boolean> = new Subject<boolean>();
public untilDestroyed = <T>(source$: Observable<T>): Observable<T> => {
return source$.pipe(takeUntil(this.destroy$));
};
public ngOnDestroy(): void {
this.destroy$.next(true);
this.destroy$.unsubscribe();
}
}
untilDestroyed
method, as when used as rxjs
operator we will lose the context unless we use arrow function.public get untilDestroyed(): <T>(source$: Observable<T>)=> Observable<T> {
return <T>(source$: Observable<T>) => source$.pipe(takeUntil(this.destroy$));
};
UnsubscribeService
to its providers
array, inject it into the constructor and apply its operator in our subscription pipe:import { Component, OnInit } from '@angular/core';
import { IntervalService } from '../services/interval/interval.service';
import { UnsubscribeService } from '../services/unsubscribe/unsubscribe.service';
@Component({
selector: 'app-careless',
template: `<p>ಠ_ಠ</p>`,
providers: [UnsubscribeService],
})
export class CarelessComponent implements OnInit {
private garbage: string[][] = [];
public constructor(private intervalService: IntervalService, private unsubscribeService: UnsubscribeService) {}
public ngOnInit(): void {
this.intervalService.getInterval.pipe(this.unsubscribeService.untilDestroyed).subscribe(async () => {
this.garbage.push(Array(5000).fill("some trash"));
});
}
}
async
pipes, no external packages needed.