在我们的应用程序中,我们有一些从BaseComponent
继承的组件。
基本组件实现OnDestroy
接口,并发出一个Subject来通知子级取消订阅最终的开放流。
这是一种可接受的方法,还是每个组件都应该有自己的ngOnDestroy
实现?从这个article中,我了解到Lifecycle挂钩是不继承的。
BaseComponent
export abstract class ComponentBase implements OnDestroy {
protected destroy$ = new Subject<boolean>();
ngOnDestroy() {
this.destroy$.next(true);
}
}
ChildComponent
export class ChildComponent extends ComponentBase implements OnInit {
ngOnInit() {
this.service
.getById(userId)
.pipe(takeUntil(this.destroy$)) // this is emitted by the parent
.subscribe(user => { ...}
}
}
答案 0 :(得分:1)
如果您使用ComponentBase
只允许您访问destroy$
,我会说这有点过头了。您可能需要扩展另一个类,而Typescript不支持多重继承,因此除非确实必要,否则请尝试避免这种情况。
也就是说,如果您只是在寻找一种以反应方式轻松退订的方法,请查看以下内容:
/**
* Easily unsubscribe from an observable stream by appending `takeUntilDestroyed(this)` to the observable pipe.
* If the component already has a `ngOnDestroy` method defined, it will call this first.
* Note that the component *must* implement OnDestroy for this to work (the typings will enforce this anyway)
*/
export function takeUntilDestroyed<T>(component: OnDestroy): (source: Observable<T>) => Observable<T> {
return (source: Observable<T>): Observable<T> => {
const onDestroy = new Subject();
const previousOnDestroy = component.ngOnDestroy;
component.ngOnDestroy = () => {
if (previousOnDestroy) {
previousOnDestroy.apply(component);
}
onDestroy.next();
onDestroy.complete();
};
return source.pipe(takeUntil(onDestroy));
};
}
然后从您的组件中执行this.myObs$.pipe(takeUntilDestroyed(this))
您也可以在此PR中找到该功能和演示用法:
https://github.com/cloudnc/ngx-sub-form/pull/41/files#diff-5796510f30fdd5bede9d709ce53ef225R45
答案 1 :(得分:0)
这是一种有效的方法,但是如果您想实现https://blog.angular-university.io/onpush-change-detection-how-it-works/,则最好使用异步管道代替订阅,并添加onPushStrategy以获得更好的性能。
答案 2 :(得分:0)
这是一种可接受的方法,还是每个组件都应该有自己的ngOnDestroy实现?
可以接受只是一个见解,但出于以下原因,我会强烈不赞成这种方法。
@Component({...})
export class MyComponent extends BaseComponent implements OnDestroy {
public ngOnDestroy() {
// do work
}
}
export class BaseComponent implements OnDestroy {
public ngOnDestroy() {
// never executed
}
}
对于上面的示例,没有发出TypeScript警告,从未执行 super 方法,因此,我很想将其称为反模式。 / p>
此外,将来您会被吸引到基类中添加其他生命周期挂钩,例如OnInit
。为此,您必须搜索所有后代,以确保它们调用super.ngOnInit()
。
虽然看起来可能需要更多工作,但使用封装更安全。
export class BaseComponent implements OnDestroy {
public ngOnDestroy() {
// do work
}
}
@Component({...})
export class MyComponent implements OnDestroy {
private readonly _base: BaseComponent = new BaseComponent();
public ngOnDestroy() {
this._base.ngOnDestroy();
}
}
网络上有很多关于封装与继承之间的优缺点的文章。实际上,这是计算机科学中冗长的讨论,并且某些编程语言由于存在问题而特别不支持继承。我想我想说的是这是一个广泛的话题,对您来说是个人选择的问题,但这部分是您提出问题的原因。
https://www.developer.com/design/article.php/3525076/Encapsulation-vs-Inheritance.htm