You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用RouteReuseStrategy复用组件时constructor与OnInit钩子是否会触发?

更新

[...]对于懒加载模块,执行shouldAttach方法时route.routeConfig.path的值为空

使用开发者显式自定义的额外数据替代route.routeConfig.path可解决该问题。

原问题

实现RouteReuseStrategy自定义路由复用策略时,观察到如下现象:

  • 进入此前已被存储待复用的组件时,OnInit和constructor会被调用
  • 离开此前已被存储待复用的组件时,OnDestroy不会被调用

从常理来看,后续需要复用的组件不触发OnDestroy是合理的。但被复用的组件仍会调用constructor和OnInit不符合预期,通常我们会在这两个函数中编写初始化逻辑,这会导致每次进入组件都表现为全新实例。

目前网上有大量RouteReuseStrategy相关教程,但未找到相关资料确认上述观察是否正确。

下方是实现的RouteReuseStrategy接口代码,MyComponent被设置为可存储复用,因此离开该组件时不会触发OnDestroy,但重新进入该组件时,它的constructor和OnInit钩子仍会被调用。

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

export class CustomRouteReuseStrategy implements RouteReuseStrategy {

    private storedRoutes = new Map<string, DetachedRouteHandle>();

    /**
     * 判定当前路由(及其子树)是否需要被分离以便后续复用
     * 如果shouldDetach返回true,我们需要存储该路由留待后续复用
     * 离开路由时触发
     */
    shouldDetach(route: ActivatedRouteSnapshot): boolean {
        if (!route.routeConfig?.path) {
            return false;
        }
        // 阻止MyComponent被销毁(不会触发OnDestroy)
        return ['my-component'].indexOf(route?.routeConfig?.path) > -1;
    }

    /**
     * 存储被分离的路由,离开路由时触发
     */
    store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
        if (!route.routeConfig?.path) {
            return;
        }
        const path = this.getPath(route);
        this.storedRoutes.set(path, handle);
    }

    /**
     * 判定当前路由(及其子树)是否需要被重新附着
     * 如果shouldAttach返回true,我们将复用之前存储的路由而非创建新组件
     * 进入路由时触发
     */
    shouldAttach(route: ActivatedRouteSnapshot): boolean {
        if (!route.routeConfig?.path) {
            return false;
        }
        const path = this.getPath(route);
        return this.storedRoutes.has(path);
    }

    /**
     * 检索此前存储的路由
     */
    retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
        if (!route.routeConfig?.path) {
            return null;
        }
        const path = this.getPath(route);
        return this.storedRoutes.get(path) || null;
    }

    /**
     * 判定两个路由是否需要复用
     * 每次路由跳转时都会触发
     */
    shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
        // 新旧路由配置相同时复用路由
        return future.routeConfig === curr.routeConfig;
    }

    private getPath(route: ActivatedRouteSnapshot): string {
        if (route.routeConfig !== null && route.routeConfig.path !== null) {
            return route.routeConfig?.path || "";
        }
        return "";
    }
}

核心疑问

  1. 被重新附着(复用)的组件是否应该触发constructor和OnInit?
  2. 如果上一问题答案为“是”,那只需要在组件首次初始化(非复用场景)执行的代码应该放在哪里?

示例说明

为了还原应用场景,示例的模块层级如下:

- app
  - home
    - manager
    - detail

每个模块都有独立路由配置:

  • / 加载 AppComponent
  • /home 加载 HomeComponent
  • /home/manager 加载 ManagerComponent
  • /home/detail 加载 DetailComponent

自定义路由策略会复用ManagerComponent,因此返回该页面时,详情列表不需要重新渲染。

复现步骤

  1. 访问 /home/manager
  2. 打开控制台查看日志输出
  3. 点击 /home/detail/1 跳转
  4. 查看控制台,可见-----> stored route with path "manager"日志输出
  5. 点击“back to manager”返回,可见控制台输出ManagerComponent.constructor和ManagerComponent.ngOnInit日志

日志显示路由已被成功附着:

  • shouldAttach(manager)
  • -----> Yes!
  • retrieve(manager)
  • -----> retrieved route with path "manager"

既然路由已经被成功附着复用,为什么ManagerComponent的constructor和OnInit还会被调用?


内容的提问来源于stack exchange,提问作者Jack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 16:15:02