首页 > 解决方案 > 防止在 JavaScript 中的代理中多次调用超级方法

问题描述

我围绕一个Component名为autodispose. 假设 class Aextendsautodispose(Component)和 class Bextends A。mixin 确保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'componentWillUnmount()两次——第一次调用Reflect.apply(target, thisArg, fnArgs),然后立即调用。我需要一种方法来检测呼叫Reflect.apply()是否已经呼叫super.componentWillUnmount()并阻止第二次呼叫。

我考虑过用另一个 Proxy 临时覆盖super.componentWillUnmount它,它设置一个它被调用的标志,但是,不出所料,你不能覆盖super的方法。

如果一切都失败了,我可以确保它autodispose不会在原型链中被调用两次,但这个解决方案会更理想。

标签: javascript

解决方案


您不需要(暂时或以其他方式)覆盖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
    }
  };
}

推荐阅读