angular - ¿Realmente es mejor usar async-pipe en lugar de subscribe() en esta situación en particular?
En mi componente recibo un Observable como un @Input().
Si el valor del Observable cambia, tengo que expandir/colapsar un acordeón de ng-bootstrap. Así que realmente no necesito el valor del Observable en la plantilla.
Este es el código, ya lo tengo:
Componente :
@Input() urlParam$!: Observable<string>;
@ViewChild('acc') accordion!: NgbAccordion;
urlParamChange$!: Observable<string>;
ngAfterViewInit(): void {
this.urlParamChange$ = this.urlParam$.pipe(
tap(urlParam => this.synchronizeAccordion(urlParam))
);
}
synchronizeAccordion(urlParam: string): void {
// do something with this.accordion
}
Y en la plantilla me suscribo mediante async pipe al urlParamChange$recién creado:
<ng-container *ngIf="(urlParamChange$ | async)"></ng-container>
<ngb-accordion #acc="ngbAccordion">
....
</ngb-accordion>
Dado que realmente no necesito el valor de urlParamChange$, lo puse en un ng-container propio, para que sea completamente independiente, pero sin embargo se llamará al método para sincronizar el acordeón.
Creo que la implementación anterior no es tan buena. Dividiste la acción en dos archivos diferentes (se necesita el tap en el componente + además el async-pipe en la plantilla).
¿No sería incluso mejor de la siguiente manera? En lugar de suscribirme con la ayuda del async-pipe, me suscribiré directamente en el ngAfterViewInit(). De esa manera puedo eliminar la variable adicional urlParamChange$y la implementación queda completamente en el método ngAfterViewInit().
Componente :
@Input() urlParam$!: Observable<string>;
@ViewChild('acc') accordion!: NgbAccordion;
ngAfterViewInit(): void {
this.urlParam$.subscribe(urlParam => this.synchronizeAccordion(urlParam));
}
synchronizeAccordion(urlParam: string): void {
// do something with this.accordion
}
Y en la plantilla, se elimina el ng-container adicional:
<ngb-accordion #acc="ngbAccordion">
....
</ngb-accordion>
En mi opinión, ambas implementaciones deberían funcionar exactamente de la misma manera. Según las Mejores Prácticas, la primera solución debería ser preferida, eso pensaría. Pero la segunda es más limpia en mi opinión.
Entonces, ¿cuál es la mejor manera de implementar un caso de uso así?
Respuesta #1
Sugiero que optes por el enfoque 2. Según tus propias admisiones, parece más claro y fácil de seguir.
Imagina que alguien llega en el futuro y ve un ng-container aleatorio con un enlace async pero sin contenido. Es muy posible que decida eliminarlo asumiendo que ya no se utiliza, en cuyo caso toda tu operación tap dejará de ejecutarse y no se generarán errores para alertarte de esto.
Mientras que alguien que lea el enfoque 2 puede ver muy fácilmente lo que está sucediendo y los resultados de modificar la suscripción son evidentes.
No hay nada de malo en darse de baja manualmente, ¡solo necesitas asegurarte de hacerlo!
Respuesta #2
¿Por qué llamas a la primera solución "mejores prácticas"? En tu caso no tiene sentido, usa la #2.