在父组件中使用单个 ngOnDestroy

Fra*_*sco 4 inheritance angular rxjs6

在我们的应用程序中,我们有一些从BaseComponent.

基础组件实现OnDestroy接口并发出一个 Subject 以通知子级取消订阅最终打开的流。

这是一种可以接受的方法还是每个组件都应该有自己的ngOnDestroy实现?从这篇文章我读到生命周期钩子不是继承的。

基础组件

export abstract class ComponentBase implements OnDestroy {
  protected destroy$ = new Subject<boolean>();

  ngOnDestroy() {
    this.destroy$.next(true);
  }
}
Run Code Online (Sandbox Code Playgroud)

子组件

export class ChildComponent extends ComponentBase implements OnInit {

 ngOnInit() {
    this.service
      .getById(userId)
      .pipe(takeUntil(this.destroy$)) // this is emitted by the parent
      .subscribe(user => { ...}
 }
}
Run Code Online (Sandbox Code Playgroud)

max*_*992 6

2020 年 9 月 9 日更新:
我们在工作中发布了一个库,可以安全地与 Ivy 一起使用,并让您可以将所有组件生命周期作为可观察对象访问:https : //github.com/cloudnc/ngx-observable-lifecycle

也就是说,应该在 Angular 本身的上游修复这个问题的 PR 最近已经合并并发布了(不记得发布了,但看看吧!)

2020 年 5 月 18 日更新:
以下内容不再适用于 Ivy,如下所述:https : //github.com/angular/angular/issues/36776

这里有一个 PR 可以恢复这种行为:https : //github.com/angular/angular/pull/35464

即使它不那么灵活,同时你可以使用这个:https : //github.com/ngneat/until-destroy


如果您使用的是ComponentBaseto 只能让您访问,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));
  };
}
Run Code Online (Sandbox Code Playgroud)

然后从你的组件中做 this.myObs$.pipe(takeUntilDestroyed(this))

您也可以在此 PR 中找到该功能和演示用法:https :
//github.com/cloudnc/ngx-sub-form/pull/41/files#diff-5796510f30fdd5bede9d709ce53ef225R45


Rea*_*lar 6

这是一种可以接受的方法还是每个组件都应该有自己的 ngOnDestroy 实现?

可接受只是一个意见问题,但我强烈反对这种方法,原因如下。

@Component({...})
export class MyComponent extends BaseComponent implements OnDestroy {
      public ngOnDestroy() {
         // do work
      }
}

export class BaseComponent implements OnDestroy {
      public ngOnDestroy() {
         // never executed
      }
}
Run Code Online (Sandbox Code Playgroud)

上面的例子没有发出关于super方法永远不会执行的TypeScript 警告,所以我很想把它称为反模式。

此外,将来你会很想添加额外的生命周期钩子,比如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();
  }
}
Run Code Online (Sandbox Code Playgroud)

网上有很多关于封装与继承之间优缺点的文章。这实际上是计算机科学中一个冗长的讨论,一些编程语言不支持继承,特别是因为这些问题。我想我是想说这是一个广泛的话题,是你个人选择的问题,但这也是你问这个问题的部分原因。

https://www.developer.com/design/article.php/3525076/Encapsulation-vs-Inheritance.htm