En una aplicación Angular , usamos un Base Component para cancelar la suscripción de la mayoría de las suscripciones observables de nuestra aplicación. Si un componente se suscribe a un observable, ese componente extend el Base Component . Mi opinión es que esto mantiene vivas las suscripciones observables hasta que se destroyed toda la aplicación, en lugar de hasta que se destruye cada componente:
base.componente.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(); } }el-resto-de-nuestros-componentes.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; }); } Si muchos componentes amplían BaseComponent y utilizan su unsubscribe$ Asunto, ¿significa eso que todas mis suscripciones solo se cancelan cuando se destruye toda la aplicación (es decir, el usuario cierra la pestaña o navega fuera de la aplicación web, por lo que Base Component se destruye), en lugar de cuando los componentes individuales se destruyen?
¿Es esta una estrategia que has visto antes, y es aconsejable? Si funciona como supongo, esto significa que todas nuestras suscripciones en la aplicación permanecerán activas hasta que se destruya toda la aplicación. Veo cómo, dependiendo de nuestras necesidades, eso puede ser algo malo o algo bueno.
Pregunta adicional: ¿ Base Component va a actuar como un singleton ? También conocido como si varios componentes extend simultáneamente BaseComponent , ¿todos usarán la misma instancia de cancelación de unsubscribe$ o habrá múltiples instancias de cancelación de unsubscribe$ (una por componente)?
Supuse que esto funcionaría, pero todos sabemos dónde te llevan las suposiciones, así que hice una prueba: https://stackblitz.com/edit/angular-ivy-ueshwz?file=src/app/extended/extended.component.ts
Funciona, ya que las suscripciones se destruyen cuando se destruyen los componentes individuales.
Creamos un servicio que contiene un tema al que podemos suscribirnos y un valor que podemos cambiar con la suscripción, para mostrar que la suscripción existe:
import { Injectable } from '@angular/core'; import { Subject } from 'rxjs/internal/Subject'; @Injectable({ providedIn: 'root' }) export class UpdateService { subject = new Subject<void>(); value = 0; }En la raíz, dispararemos al sujeto cada segundo y tendremos un componente que podemos activar y desactivar.
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>Luego, usaremos un componente extendido para marcar ese valor en 1 con una suscripción
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>Claro, cerrar el componente detiene el ticker, por lo que la suscripción se canceló.
Pregunta adicional: BaseComponent no actúa como un singleton, cuando crea una instancia de un objeto, no crea instancias compartidas de clases principales. Extender una clase solo agrega propiedades y métodos a esa instancia.
No estoy seguro de recomendar esto, si alguien anula ngOnDestroy() necesita llamar a super.ngOnDestroy() , que puede ser fácil de olvidar. Son solo cuatro líneas de código, probablemente sea mejor ponerlo explícitamente en cada componente que lo necesite. Las suscripciones manuales deberían ser bastante raras de todos modos, si está utilizando la tubería async .
Resolví esto en un proyecto haciendo lo siguiente:
En base.component :
private sub: any = {}; ngOnDestroy() { Object.keys(this.sub).map(item => { this.sub[item].unsubscribe(); }) }Luego, en cualquier componente que se extienda:
this.sub.myService = this.myService.doStuff$.subscribe(......Con este método, la suscripción permanece activa hasta que se destruye el componente.