Angular路由keepAlive

255 阅读5分钟

RouteReuseStrategy 是 Angular 提供的一个服务类,用于自定义路由复用策略。通过它,你可以控制路由组件的缓存、销毁以及重新加载行为。默认情况下,Angular 会在路由切换时销毁当前组件并创建新组件。而通过 RouteReuseStrategy,你可以改变这种行为,比如缓存某些路由的组件实例,以优化性能或提升用户体验。

RouteReuseStrategy 的核心方法

RouteReuseStrategy 是一个抽象类,需要实现以下方法:

shouldDetach(route: ActivatedRouteSnapshot): boolean

  • 是否将当前路由的组件缓存下来。

  • 返回值:true 表示需要缓存,false 表示不缓存。

store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void

  • 缓存组件实例。

  • 参数:

    • route:当前路由的快照。

    • handle:组件实例的引用。

shouldAttach(route: ActivatedRouteSnapshot): boolean

  • 是否需要从缓存中加载组件实例。

  • 返回值:true 表示从缓存中加载,false 表示重新创建。

retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null

  • 获取缓存中的组件实例。

  • 返回值:缓存的组件实例引用,或者 null(如果没有缓存)。

shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean

  • 是否复用当前路由。

  • 参数:

    • future:将要导航到的路由快照。

    • curr:当前路由快照。

  • 返回值:true 表示复用,false 表示重新加载。

简单示例

实现一个基础的路由复用策略

import { RouteReuseStrategy, DetachedRouteHandle, ActivatedRouteSnapshot } from '@angular/router';

export class CustomRouteReuseStrategy implements RouteReuseStrategy {
  private storedRoutes: { [key: string]: DetachedRouteHandle } = {};

  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    // 控制需要缓存的路由,假设只有路径 'dashboard' 需要缓存
    return route.routeConfig?.path === 'dashboard';
  }

  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
    // 将路由组件缓存起来
    this.storedRoutes[route.routeConfig?.path || ''] = handle;
  }

  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    // 如果缓存中有对应的路由组件实例,就复用
    return !!this.storedRoutes[route.routeConfig?.path || ''];
  }

  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
    // 返回缓存的路由组件实例
    return this.storedRoutes[route.routeConfig?.path || ''] || null;
  }

  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    // 当路由路径相同时复用路由
    return future.routeConfig === curr.routeConfig;
  }
}

在模块中启用自定义策略

将自定义的 RouteReuseStrategy 添加到 providers 中:

import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { CustomRouteReuseStrategy } from './custom-route-reuse-strategy';

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  providers: [
    { provide: RouteReuseStrategy, useClass: CustomRouteReuseStrategy }
  ],
  exports: [RouterModule]
})
export class AppRoutingModule {}

方法之间的关系

RouteReuseStrategy 的核心方法之间有明确的联系,它们共同决定了路由组件是否被缓存、是否从缓存中加载、何时复用等。可以把它们看作一个生命周期流转的过程,每个方法在不同的阶段起到不同的作用。

方法之间的关系和调用顺序

当导航到一个新的路由时,RouteReuseStrategy 的方法会按照以下流程被调用:

1. shouldReuseRoute

  • 触发时机:Angular 判断当前路由和目标路由是否相同时,会调用此方法。

  • 作用:决定是否复用当前路由。

  • 如果返回 true,则当前组件不会被销毁,路由直接复用,不会触发其他方法。

  • 如果返回 false,则进入路由切换流程,触发其他方法。

联系:它是整个复用策略的第一步。如果返回 false,Angular 会检查是否需要缓存当前路由组件(进入下一步的 shouldDetach)。

2. shouldDetach

  • 触发时机:在路由切换之前,判断是否需要将当前路由组件缓存。

  • 作用:返回 true 时,Angular 会缓存当前路由组件实例,并调用 store 方法。

联系:如果 shouldDetach 返回 false,当前路由组件会被销毁,不会触发后续的 store 方法。

3. store

  • 触发时机:shouldDetach 返回 true 后,Angular 会调用 store 方法,将当前路由组件实例缓存起来。

  • 作用:将当前路由的组件实例存储到一个容器中(例如对象或 Map)。

  • 联系:它依赖于 shouldDetach 的返回值,缓存组件实例供后续的 shouldAttach 和 retrieve 使用。

4. shouldAttach

  • 触发时机:当切换到目标路由时,判断是否需要从缓存中加载组件实例。

  • 作用:返回 true 时,Angular 会调用 retrieve 方法,从缓存中获取组件实例。

联系:如果 shouldAttach 返回 false,Angular 会重新创建目标路由的组件,而不会调用 retrieve。

5. retrieve

  • 触发时机:shouldAttach 返回 true 后,Angular 会调用 retrieve 方法,获取缓存的组件实例。

  • 作用:从 store 方法保存的缓存中取出组件实例,供路由复用使用。

联系:它依赖于 shouldAttach 的返回值。如果返回 null,Angular 会重新创建目标组件。

流程总结

用户导航 ->
  shouldReuseRoute
    └── true: 当前路由复用,流程结束
    └── false: 路由切换
          |
  shouldDetach
    └── true: 缓存组件 -> 调用 store
    └── false: 销毁组件
          ↓
目标路由 ->
  shouldAttach
    └── true: 从缓存加载 -> 调用 retrieve
    └── false: 创建新组件

方法间的实际联系

  1. 决定是否缓存的链路:
  • shouldReuseRoute 返回 false → 检查 shouldDetach。

  • 如果 shouldDetach 返回 true,则缓存组件实例,并调用 store。

  1. 决定是否复用的链路:
  • 进入目标路由时,检查 shouldAttach。

  • 如果 shouldAttach 返回 true,则调用 retrieve 获取缓存实例。

  1. 缓存与复用的桥梁:
  • store 和 retrieve 是缓存组件实例的核心,store 负责存,retrieve 负责取。
  1. 复用前的终止条件:
  • 如果 shouldReuseRoute 返回 true,整个流程提前结束,既不缓存当前组件,也不会加载缓存。

示例:它们如何配合?

假设我们希望缓存 dashboard 路由的组件,流程可能如下:

  1. 用户离开 dashboard 路由,进入其他路由:

• shouldReuseRoute 返回 false。

• shouldDetach 返回 true,调用 store 缓存组件实例。

  1. 用户返回 dashboard 路由:

• shouldReuseRoute 返回 false。

• shouldAttach 返回 true,调用 retrieve,从缓存加载组件实例。

总结

• RouteReuseStrategy 的方法不是孤立的,它们形成一个完整的复用逻辑链路。

• shouldDetach 和 store 决定当前组件是否缓存,shouldAttach 和 retrieve 决定目标组件是否从缓存中加载。

• shouldReuseRoute 是一个优先级最高的判断,决定是否完全跳过复用策略。

一般情况下,shouldReuseRoute 方法默认内容如下,一般不需要修改:

shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
    this.nextRoute = future;
    return future.routeConfig === curr.routeConfig;
  }