Angular2+ routeReuseStrategy 生命周期钩子

Angular2+ routeReuseStrategy lifecycle hooks

我正在尝试利用自定义 RouteReuseStrategy 为此,我想在组件分离时暂停任何订阅,以及滚动到正确位置等其他事情。

我已经检查了可能的挂钩,但显然没有其他 lifecycle hooks have been added and OnDestroy 未被调用。

我尝试添加自己的 onDetach 和 onAttach 挂钩,但是 ActivatedRouteSnapshots nor the DetachedRouteHandle 都不会给我当前组件的实例(只是原型?)。

这是我在使用 CanDeactivate guard 导航离开时掌握组件实例的唯一方法,但这似乎不对。而且我仍然找不到为 onAttach 添加挂钩的方法。

所以我的问题是,如何在分离时正确挂起组件并在附加时恢复它?

@angular/router 中曾经有一个 OnActivate 挂钩接口,但它似乎消失了,我没有看到任何替代品。

P.S。似乎有一些报告称 Angular 具有自定义 RouteReuseStrategies 的应用程序在长时间使用时速度变慢,可能是因为无法 pause/resume 组件。

我修复了它(是的,与其说是缺失的功能,不如说这是一个错误)。

扩展 RouterOutlet 并覆盖 attach()detach()(见下文),然后用 <app-router-outlet> 替换您的 <router-outlet> 标签。 如果您的组件有 onDetach and/or onAttach(ref: ComponentRef<any>, activatedRoute: ActivatedRoute) 方法,它将被调用。

import {ComponentRef, Directive} from '@angular/core';
import {ActivatedRoute, RouterOutlet} from '@angular/router';

@Directive({
  selector: 'app-router-outlet',
})
export class AppRouterOutletDirective extends RouterOutlet {

  detach(): ComponentRef<any> {
    const instance: any = this.component;
    if (instance && typeof instance.onDetach === 'function') {
      instance.onDetach();
    }
    return super.detach();
  }

  attach(ref: ComponentRef<any>, activatedRoute: ActivatedRoute): void {
    super.attach(ref, activatedRoute);
    if (ref.instance && typeof ref.instance.onAttach === 'function') {
      ref.instance.onAttach(ref, activatedRoute);
    }
  }
}

P.S。即使有了这个修复,自定义 RouteReuseStrategies 仍然毫无用处,无法访问 history states 或在 ActivatedRoute 中保留 data,无法识别具有相同 routeConfig/path 的两个实例。

再加上 angular 调用 RouteReuseStrategy、路由器导航事件和 history.pushState 的一些奇怪时间,很难为此编写解决方法。

处理起来非常令人沮丧。

我将 Su-An Hwang 的答案扩展为不直接使用指令扩展路由器出口,而只是使用一个额外的属性来添加生命周期挂钩。

这应该可以减少在应用中添加额外的生命周期挂钩的侵入性。

@Directive({
  selector: '[appRouteReuseLifecycle]',
})
export class RouteReuseLifeCycleDirective {
  constructor(private routerOutlet: RouterOutlet) {
    // Methods need to be patched before content init
    this.patchMethods();
  }

  /**
   * This method patches both onDetach and onAttach methods to call the relevant
   * hooks in the child component before or after running the existing logic
   * @private
   */
  private patchMethods() {
    // Save the original attach method
    const originalAttach = this.routerOutlet.attach;
    // Override the component method
    this.routerOutlet.attach = (ref: ComponentRef<any>, activatedRoute: ActivatedRoute) => {
      originalAttach.bind(this.routerOutlet)(ref, activatedRoute);
      // Call the onAttach hook if exists
      const instance = this.routerOutlet.component as ComponentWithOptionalLifecycleHooks;
      if (instance && typeof instance.onAttach === 'function') {
        instance.onAttach();
      }
    };

    // Save the original detach method
    const originalDetach = this.routerOutlet.detach;
    this.routerOutlet.detach = () => {
      const instance = this.routerOutlet.component as ComponentWithOptionalLifecycleHooks;
      if (instance && typeof instance.onDetach === 'function') {
        instance.onDetach();
      }
      // return the detached component with the original method
      return originalDetach.bind(this.routerOutlet)();
    };
  }
}

interface ComponentWithOptionalLifecycleHooks {
  onAttach?: () => void;
  onDetach?: () => void;
}