Предотвратить многократный вызов суперметода в прокси в JavaScript - PullRequest
0 голосов
/ 13 июля 2020

Я написал миксин декоратора TypeScript / JavaScript вокруг React Component под названием autodispose. Предположим, что класс A расширяет autodispose(Component), а класс B расширяет A. Миксин гарантирует, что A.componentWillUnmount() вызывается независимо от того, вызывает ли B.componentWillUnmount() super.componentWillUnmount() через прокси.

(Код находится на TypeScript, но вопрос относится к JavaScript.)

export function autodispose<
  T extends Class<React.Component>
>(Target: T) {
  const ObservingComponent = class extends Target {
    constructor(...args: any[]) {
      super(...args);

      // ... mixin setup ...

      this.componentWillUnmount = new Proxy(this.componentWillUnmount, {
        apply: (target, thisArg, fnArgs) => {
          Reflect.apply(target, thisArg, fnArgs);

          if (super.componentWillUnmount) {
            super.componentWillUnmount();
          }

          this.__mixinCleanup();
        },
      });
    }

    componentWillUnmount() {
      if (super.componentWillUnmount) {
        super.componentWillUnmount();
      }

      this.__mixinCleanup();
    }

    private __mixinCleanup() {
      // is a no-op if __mixinCleanup() has already been called
      // ...
    }
  };
}

Если B вызывает super.componentWillUnmount(), тогда прокси вызовет A s componentWillUnmount() дважды - сначала по Reflect.apply(target, thisArg, fnArgs), а затем сразу после этого. Мне нужен способ определить, вызвал ли вызов Reflect.apply() уже super.componentWillUnmount(), и предотвратить второй вызов.

Я рассмотрел возможность временного переопределения super.componentWillUnmount другим прокси-сервером, который устанавливает флаг, который он был вызван, но, что неудивительно, вы не можете переопределить методы super.

Если ничего не помогает, я могу просто убедиться, что autodispose не вызывается в цепочке прототипов дважды, но это решение было бы более идеальным.

1 Ответ

0 голосов
/ 13 июля 2020

Вам не нужно (временно или иначе) перезаписывать B s super.componentWillUnmount - вы сами определили A.prototype.componentWillUnmount! Вы можете просто установить там флаг:

export function autodispose(Target) {
  return class ObservingComponent extends Target {
    constructor(...args) {
      super(...args);
      // ... mixin setup ...

      this._hasSuperBeenCalled = false;
      let original = this.componentWillUnmount;
      this.componentWillUnmount = function(...args) {
        this._hasSuperBeenCalled = false;
        original.apply(this, args);
        if (!this._hasSuperBeenCalled)
          throw new Error(`Warning: ${this.constructor.name}.componentWillUnmount forgot its super call`);
      };
    }

    componentWillUnmount() {
      this._hasSuperBeenCalled = true;
      if (super.componentWillUnmount) {
        super.componentWillUnmount();
      }

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