Убедитесь, что super.onDestroy () в производном компоненте - PullRequest
0 голосов
/ 04 марта 2019

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

abstract class BaseComponent implements OnDestroy {
   subscriptions = new Array<Subscription>();
   get model() { return … }

   ngOnDestroy() {
      for (let s of subscriptions) s.unsubscribe();
   }
}

, однако, когда разработчики пишут собственный метод onOnDestroy в конкретном компоненте, который расширяетComponentBase, он не знает, что ему нужно позвонить super.ngOnDestroy();

Есть ли какой-нибудь (машинописный) способ обеспечить предупреждение?Или образец другого компонента наследования?может быть, модульный тест, который будет проверять ngOnDestroy на всех компонентах, которые расширяют BaseComponent?

Ответы [ 4 ]

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

Я знаю, что уже поздно .. но для того, кому это нужно. !!!

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();
    };
 }
}

Подробное описание можно найти здесь

0 голосов
/ 04 марта 2019

Большинство языков ООП не предоставляют функцию, которую вы ищете.Как только метод переопределяется дочерним классом, невозможно обеспечить принудительное выполнение дочерней реализацией родительской реализации.В машинописи есть открытый вопрос , обсуждающий эту функцию.

Другой подход заключается в том, чтобы пометить реализацию ngOnDestroy для базового класса как final и дать baseКлассы метод подключения, чтобы позволить им делегировать логику разрыва.Например:

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 не поддерживает эквивалент конечного логического банкомата .

Еще одним интересным моментом является тот факт,что эта ваша проблема возникает из-за того, как вы планируете управлять подписками на экземплярах компонентов.Есть действительно лучшие способы сделать это, один из них - взять элемент из исходных наблюдаемых до тех пор, пока компонент не будет уничтожен.Что-то вроде:

readonly observable$: Observable<string> = ....;
ngOnInit(){
   observable$.pipe(takeUntil(/*this instance is destroyed*/)).subscribe(...)
}

Это может быть легко заархивировано с библиотеками, такими как this

0 голосов
/ 04 марта 2019

Самое простое решение - определить тип возврата 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;
}
0 голосов
/ 04 марта 2019

Вы можете гарантировать, что разработчики никогда не напишут subscribe в компонентах, чтобы избежать необходимости отписываться.

Это означает, что вы бы в полной мере использовали реактивное программирование с операторами rxjs и асинхронными каналами.

Вы также можете использовать собственный декоратор класса, который проверяет всех членов класса и проверяет, являются ли они экземплярами подписок.

Наконец-то вы можете использовать пользовательский оператор rxjs, который отписывается после уничтожения вашего компонента.

Доступно несколько вариантов, но я бы порекомендовал использовать первый, так как он делает ваш код чище и читается для стратегии обнаружения изменений onPush.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...