Ionic/Angular自定义RouteReuseStrategy出现不兼容复用策略错误
解决Angular Ionic PWA中自定义RouteReuseStrategy导致的"incompatible reuse strategy"错误
问题背景
开发的PWA底部标签栏使用replaceUrl导航,按下硬件返回键可退出应用。为避免三个标签组件切换时被销毁,自定义了CustomRouteReuseStrategy,但切换标签时触发错误:
Error: Uncaught (in promise): Error: incompatible reuse strategy
相关代码
tabs.page.html
<ion-tabs > <ion-tab-bar slot="bottom"> <ion-tab-button (click)="goTo('home')"> <ion-icon name="home"></ion-icon> <ion-label>{{'TABS.home' | translate}}</ion-label> </ion-tab-button> <ion-tab-button (click)="goTo('shopping')"> <ion-icon name="card"></ion-icon> <ion-label>{{'TABS.shop' | translate}}</ion-label> </ion-tab-button> <ion-tab-button (click)="goTo('profile')"> <ion-icon name="person"></ion-icon> <ion-label>{{'TABS.me' | translate}}</ion-label> </ion-tab-button> </ion-tab-bar> </ion-tabs>
tabs.page.component.ts
goTo(place: string){ this.router.navigate(['tabs/'+place],{replaceUrl: true}); }
自定义CustomRouteReuseStrategy
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy,} from '@angular/router'; export class CustomRouteReuseStrategy implements RouteReuseStrategy { private routeStore = new Map<string, DetachedRouteHandle>(); shouldDetach(route: ActivatedRouteSnapshot): boolean { const path = route.routeConfig!.path!; return path!=null && ['', 'home', 'shopping', 'profile'].includes(path); } store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void { this.routeStore.set(route.routeConfig!.path!, handle); } shouldAttach(route: ActivatedRouteSnapshot): boolean { const path = route.routeConfig!.path!; return ( !!path && ['', 'home', 'shopping', 'profile'].includes(path) && !!this.routeStore.get(path) ); } retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null{ const path = route.routeConfig!.path!; const result = this.routeStore.get(path); if(result == undefined){ return null; }else{ return result; } } shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { return future.routeConfig === curr.routeConfig; } }
路由配置
app.routing.module.ts
const routes: Routes = [ { path: '', loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule) }, { path: 'tabs', loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule) } ]
tabs.routing.module.ts
const routes: Routes = [ { path: 'tabs', component: TabsPage, children: [ { path: 'home', loadChildren: () => import('../home/home.module').then((m) => m.HomePageModule), ...canActivate(redirectUnauthorizedToLogin), }, { path: 'shopping', loadChildren: () => import('../shopping/shopping.module').then((m) => m.ShoppingPageModule), ...canActivate(redirectUnauthorizedToLogin), }, { path: 'profile', loadChildren: () => import('../profile/profile.module').then((m) => m.ProfilePageModule), ...canActivate(redirectUnauthorizedToLogin), }, // ...其他子路由 { path: '', redirectTo: '/tabs/home', pathMatch: 'full', }, ], }, { path: '', redirectTo: '/tabs/home', pathMatch: 'full', }, { path: 'not-found', loadChildren: () => import('../page-not-found/page-not-found.module').then( (m) => m.PageNotFoundPageModule ), }, { path: '**', redirectTo: '/not-found', pathMatch: 'full' }, ];
解决方案
错误核心是自定义复用策略与replaceUrl: true导航冲突,同时路由配置和路径匹配逻辑存在问题,按以下步骤修复:
1. 修正shouldReuseRoute方法逻辑
原方法仅通过routeConfig判断路由复用,结合replaceUrl导航时会触发上下文不兼容错误,修改为同时匹配路由路径:
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { const sameConfig = future.routeConfig === curr.routeConfig; const samePath = future.url.join('/') === curr.url.join('/'); return sameConfig || samePath; }
2. 调整复用策略的路径判断逻辑
原策略包含空路径(重定向路由,无需复用),且未结合父路由判断完整路径,修改为匹配完整路由路径:
shouldDetach(route: ActivatedRouteSnapshot): boolean { const fullPath = route.pathFromRoot.map(r => r.routeConfig?.path || '').filter(Boolean).join('/'); return ['tabs/home', 'tabs/shopping', 'tabs/profile'].includes(fullPath); } store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void { const fullPath = route.pathFromRoot.map(r => r.routeConfig?.path || '').filter(Boolean).join('/'); this.routeStore.set(fullPath, handle); } shouldAttach(route: ActivatedRouteSnapshot): boolean { const fullPath = route.pathFromRoot.map(r => r.routeConfig?.path || '').filter(Boolean).join('/'); return ['tabs/home', 'tabs/shopping', 'tabs/profile'].includes(fullPath) && !!this.routeStore.get(fullPath); } retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null{ const fullPath = route.pathFromRoot.map(r => r.routeConfig?.path || '').filter(Boolean).join('/'); return this.routeStore.get(fullPath) || null; }
3. 优化路由导航与返回键逻辑(可选)
保留返回键退出功能的同时,移除replaceUrl避免冲突,在TabsPage中监听硬件返回事件:
import { Platform } from '@ionic/angular'; import { Router } from '@angular/router'; constructor(private platform: Platform, private router: Router) { this.platform.backButton.subscribeWithPriority(10, () => { if (this.router.url === '/tabs/home') { navigator['app'].exitApp(); } else { this.router.navigate(['/tabs/home']); } }); } goTo(place: string){ this.router.navigate(['tabs/'+place]); }
4. 清理重复路由配置
删除app.routing.module中重复的tabs路由加载项:
const routes: Routes = [ { path: '', loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule) } ]
验证修复
修改完成后,切换标签页时组件会被正确复用,不再触发"incompatible reuse strategy"错误,硬件返回键仍可正常退出应用。
内容的提问来源于stack exchange,提问作者sirss
相关产品推荐
相关产品推荐

