javascript - Menggunakan komponen dasar untuk berhenti berlangganan dari semua langganan observable
Dalam aplikasi Angular, kami menggunakan Base Component untuk berhenti berlangganan dari sebagian besar subscription observable di aplikasi kami. Jika sebuah komponen berlangganan ke sebuah observable, komponen tersebut akan extend Base Component. Pemikiran saya adalah bahwa ini menjaga subscription observable tetap hidup sampai seluruh aplikasi destroyed, bukan sampai masing-masing komponen dihancurkan:
base.component.ts: :
import { Subject } from 'rxjs';
import { OnDestroy, Component } from '@angular/core';
export abstract class BaseComponent implements OnDestroy {
protected unsubscribe$ = new Subject<void>();
ngOnDestroy(): void {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
}
the-rest-of-our-components.ts: :
import { Component, OnInit } from '@angular/core';
import { MyService } from 'src/app/services/my.service';
import { BaseComponent } from '../base/component/base-component';
export class myComponent extends BaseComponent implements OnInit {
myProperty: string;
constructor(
private myService: MyService,
) {
super();
}
ngOnInit(): void {
this.myService.doStuff$
.pipe(takeUntil(this.unsubscribe$)) // take until baseComponent's unsubscribe$
.subscribe((data) => {
this.myProperty = data;
});
}
Jika banyak komponen memperluas BaseComponent dan menggunakan unsubscribe$ Subject-nya, apakah itu berarti semua langganan saya hanya dibatalkan ketika seluruh aplikasi dihancurkan (alias pengguna menutup tab atau berpindah dari aplikasi web, sehingga BaseComponent dihancurkan), bukan ketika komponen individu dihancurkan?
Apakah ini strategi yang pernah Anda lihat sebelumnya, dan apakah itu disarankan? Jika itu bekerja seperti yang saya asumsikan, ini berarti semua langganan kami di seluruh aplikasi tetap aktif sampai seluruh aplikasi dihancurkan. Saya melihat bagaimana, tergantung pada kebutuhan kami, itu bisa menjadi hal yang buruk atau hal yang baik.
Pertanyaan bonus: apakah Base Component akan bertindak seperti singleton? Dengan kata lain, jika beberapa komponen secara bersamaan extend BaseComponent, apakah mereka semua akan menggunakan instance yang sama dari unsubscribe$ atau akan ada beberapa instance dari unsubscribe$ (satu untuk setiap komponen)?
Jawaban #1
Saya mengira ini akan berhasil, tapi kita semua tahu ke mana asumsi membawa Anda, jadi saya membuat sebuah tes: https://stackblitz.com/edit/angular-ivy-ueshwz?file=src/app/extended/extended.component.ts
Ini berhasil, seperti halnya langganan akan dihancurkan ketika komponen individual dihancurkan.
Kami membuat sebuah layanan yang memegang subjek yang dapat kami langgani, dan sebuah nilai yang dapat kami ubah dengan langganan tersebut, untuk menunjukkan bahwa langganan itu ada:
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/internal/Subject';
@Injectable({ providedIn: 'root' })
export class UpdateService {
subject = new Subject<void>();
value = 0;
}
Di root kita akan menembakkan subjek setiap detik, dan memiliki sebuah komponen yang bisa kita nyalakan dan matikan
export class AppComponent implements OnInit {
extCompOpen = true;
constructor(public update: UpdateService) {}
ngOnInit() {
interval(1000).subscribe(() => this.update.subject.next());
}
}
<app-extended *ngIf="extCompOpen"></app-extended>
<button (click)="extCompOpen = !extCompOpen">Toggle Component</button>
<p>This counter will keep going up as long as the subscription exists:</p>
<p>{{ update.value }}</p>
Lalu kita akan menggunakan komponen yang diperluas untuk menambah nilai itu sebesar 1 dengan sebuah langganan
export class ExtendedComponent extends BaseComponent implements OnInit {
constructor(private update: UpdateService) {
super();
}
ngOnInit() {
this.update.subject.pipe(takeUntil(this.unsubscribe$)).subscribe(() => {
this.update.value++;
});
}
}
<p>Extended component exists!</p>
Keren, menutup komponen menghentikan ticker, jadi langganan telah dibatalkan.
Pertanyaan bonus: BaseComponent tidak berperilaku seperti singleton, ketika Anda membuat sebuah instance dari suatu objek, itu tidak membuat instance yang dibagi dari kelas induk. Memperluas sebuah kelas hanya menambahkan properti dan metode ke instance tersebut.
Saya tidak yakin apakah saya akan merekomendasikan ini, jika seseorang menimpa ngOnDestroy() mereka perlu memanggil super.ngOnDestroy(), yang mungkin mudah terlupakan. Hanya terdiri dari empat baris kode, mungkin lebih baik menaruhnya secara eksplisit di setiap komponen yang membutuhkannya. Langganan manual seharusnya cukup jarang, jika Anda menggunakan async pipe.
Jawaban #2
Saya menyelesaikan ini dalam sebuah proyek dengan melakukan hal berikut:
Di base.component:
private sub: any = {};
ngOnDestroy() {
Object.keys(this.sub).map(item => {
this.sub[item].unsubscribe();
})
}
Kemudian di komponen mana pun yang diperluas:
this.sub.myService = this.myService.doStuff$.subscribe(......
Dengan metode ini, langganan tetap aktif hingga komponennya dihancurkan.
