Использование одного ngOnDestroy в родительском компоненте - PullRequest
1 голос
/ 31 мая 2019

В нашем приложении есть некоторые компоненты, которые наследуются от BaseComponent.

Базовый компонент реализует интерфейс OnDestroy и генерирует объект Subject, чтобы уведомить дочерние элементы о том, чтобы отписаться от возможных открытых потоков.

Это приемлемый подход или, скорее, каждый отдельный компонент должен иметь свою собственную реализацию ngOnDestroy? Из этой статьи я прочитал, что хуки жизненного цикла не унаследованы.

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 ]

2 голосов
/ 31 мая 2019

Если вы используете 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 голос
/ 31 мая 2019

Это приемлемый подход или, скорее, каждый отдельный компонент должен иметь свою собственную реализацию ngOnDestroy?

Допустимо, это просто вопрос мнения, но я бы решительно не поощряйте такой подход по следующей причине:

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

export class BaseComponent implements OnDestroy {
      public ngOnDestroy() {
         // never executed
      }
}

В приведенном выше примере не выдано предупреждение TypeScript о том, что метод super никогда не выполняется, и поэтому я хотел бы вызвать его anti-pattern .

Кроме того, в будущем у вас будет искушение для добавления дополнительных хуков жизненного цикла, таких как 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

0 голосов
/ 31 мая 2019

Это правильный подход, но лучше использовать асинхронный канал вместо подписки и добавить onPushStrategy для повышения производительности, если вы хотите достичь https://blog.angular -university.io / onpush-change-detection-how-it-Работаю / .

...