我有一堆具有非常相似的生命周期逻辑的组件,因此我创建了实现OnDestroy
abstract class BaseComponent implements OnDestroy {
subscriptions = new Array<Subscription>();
get model() { return … }
ngOnDestroy() {
for (let s of subscriptions) s.unsubscribe();
}
}
但是,当开发人员在扩展了ComponentBase
的具体组件中编写自定义onOnDestroy方法时,他无法知道需要调用super.ngOnDestroy()
;
是否有某种(打字稿)方式来确保警告?还是模式其他组件继承?
也许可以对扩展ngOnDestroy
的所有组件进行BaseComponent
测试的单元测试?
答案 0 :(得分:1)
大多数OOP语言不提供您要寻找的功能。一旦方法被子类覆盖,就无法强制子方法调用父实现。在打字稿中有an open issue在讨论此功能。
另一种方法是将基类上ngOnDestroy的实现标记为 final ,并为基类提供一种连接方法,以允许它们委派拆卸逻辑。例如:
abstract class BaseComponent implements OnDestroy {
readonly subscriptions = new Array<Subscription>();
get model() { return … }
ngOnDestroy() {
for (let s of subscriptions) s.unsubscribe();
this.destroyHook();
}
// depending on your needs, you might want to have a default NOOP implementation
// and allow child classes to override it. That way you wont need to spread NOOP
// implementations all over your code
abstract protected destroyHook(): void;
}
class ChildClass extends BaseComponent {
protected destroyHook(){//NOOP}
}
ts doesnt support an equivalent of the final logic ATM。
另一个有趣的事实是,您遇到的这个问题来自您计划如何管理组件实例上的订阅。确实有更好的方法来执行此操作,其中一种方法是从源可观察对象直到中获取元素,直到该组件被破坏。像这样:
readonly observable$: Observable<string> = ....;
ngOnInit(){
observable$.pipe(takeUntil(/*this instance is destroyed*/)).subscribe(...)
}
可以使用this
之类的库轻松对其进行存档。答案 1 :(得分:1)
最简单的解决方案是定义孩子也需要返回的返回类型ngOnDestroy
。
class REQUIRED_SUPER {} //important to not export it, only we should be able to create it.
class Base implements OnDestroy {
ngOnDestroy(): REQUIRED_SUPER {
return new REQUIRED_SUPER;
}
}
因此,如果您的用户也没有返回它,则意味着他没有调用您的方法。
export class Child extends Base implements OnDestroy {
ngOnDestroy(): REQUIRED_SUPER {
}
}
这导致TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
要解决此问题,您的用户需要这样做:
ngOnDestroy(): REQUIRED_SUPER {
return super.ngOnDestroy();
}
或
ngOnDestroy(): REQUIRED_SUPER {
const superCalled = super.ngOnDestroy();
//to stuff
return superCalled;
}
答案 2 :(得分:0)
您可以确保开发人员从不在组件中编写subscribe
,这样可以避免退订。
这意味着您将通过rxjs运算符和异步管道充分使用反应式编程。
您还可以使用自定义类装饰器来测试所有类成员,并查看它们是否为订阅实例。
您最终可以使用自定义的rxjs运算符,一旦您的组件遭到破坏,该运算符便会取消订阅。
它们有几个可用的选项,但是我建议使用第一个,因为它可以使您的代码更整洁并阅读onPush更改检测策略。
答案 3 :(得分:0)
我知道它晚了..但是对于需要它的人来说。!!!
export abstract class BaseClass implements OnDestroy {
ngOnDestroy(): void { }
constructor() {
const refOnDestroy = this.ngOnDestroy;
this.ngOnDestroy = () => {
refOnDestroy();
// perform unsubscriptions here
// eg: for (let s of subscriptions) s.unsubscribe();
};
}
}