Angular2+ routeReuseStrategy 生命周期钩子

Posted

技术标签:

【中文标题】Angular2+ routeReuseStrategy 生命周期钩子【英文标题】:Angular2+ routeReuseStrategy lifecycle hooks 【发布时间】:2018-03-13 04:05:19 【问题描述】:

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

我检查了可能的钩子,但显然没有添加额外的lifecycle hooks,也没有调用OnDestroy。

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

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

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

以前在@angular/router 中有一个OnActivate 钩子接口,但好像没有了,我没有看到任何替代。

附:似乎有一些报告称,带有自定义 RouteReuseStrategies 的 Angular 应用程序在长时间使用时会变慢,这可能是因为无法暂停/恢复组件。

【问题讨论】:

【参考方案1】:

我扩展了 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;

【讨论】:

不幸的是,这会引发构建错误:无法绑定到“appRouteReuseLifecycle”,因为它不是“router-outlet”的已知属性。你有解决办法吗? 解决了这个问题。确保使用&lt;router-outlet appRouteReuseLifecycle&gt; 而不是&lt;router-outlet [appRouteReuseLifecycle]&gt; 我每次都犯这个错误哈哈【参考方案2】:

我修复了它(是的,这更像是一个错误而不是缺少的功能)。

扩展 RouterOutlet 并覆盖 attach()detach()(见下文),然后将 &lt;router-outlet&gt; 标签替换为 &lt;app-router-outlet&gt;。 如果您的组件有 onDetach 和/或 onAttach(ref: ComponentRef&lt;any&gt;, 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);
    
  

附:即使进行了修复,自定义 RouteReuseStrategies 仍然毫无用处,如果无法访问 history states 或在 ActivatedRoute 中保留 data,则无法识别具有相同 routeConfig/path 的两个实例。

再加上 Angular 调用 RouteReuseStrategy、Router Navigation Events 和 history.pushState 的一些奇怪时机,很难为此编写解决方法。

处理起来非常令人沮丧。

【讨论】:

感谢您的出色工作和分享。只是想知道您如何处理app-router-outlet 不是已知元素的错误 - 如github.com/angular/angular/issues/12920 中提到的那样无法识别? @HoangDucNguyen 我从来没有遇到过这个问题,您确定您已将其添加到您的app.module.ts declarations 下吗? 我添加了。问题仍然存在 谢谢,我再次检查了@Directive 本身的声明不正确。我将 angular-cli selector: '[appCustomRouterOutlet]' 生成的修改为 selector: 'app-custom-router-outlet',现在可以使用了 但它只有在我将指令移动到共享模块下并将该共享模块导入应用程序模块时才有效

以上是关于Angular2+ routeReuseStrategy 生命周期钩子的主要内容,如果未能解决你的问题,请参考以下文章

Angular2 [innerHtml] angular2 标签不起作用

Angular2 Dart - 在 Angular2 组件中获取文本

RangeError,谷歌地图方向服务。 angular2, SebastianM/angular2-google-maps

angular2 datePipe IOS不兼容问题

从“@angular”而不是“angular2”导入 *

angular2过滤问题