在父组件中使用单个ngOnDestroy

时间:2019-05-31 13:19:15

标签: angular inheritance rxjs6

在我们的应用程序中,我们有一些从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 => { ...}
 }
}

3 个答案:

答案 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