如何通过NgRx-router-store将NavigationExtras存入状态管理仓库?
我来帮你搞定这个困扰!你当前用history.state的问题根源在于时机不匹配:当RouterStateSerializer执行serialize方法时,当前导航还未完全完成,浏览器的history.state还停留在上一次导航的状态,自然会拿到"下一次"的内容。下面给你两种可行的解决思路:
方案一:通过Effect捕获NavigationExtras并存入Store
这种方式不需要修改Serializer,而是利用NgRx的Effect监听导航事件,直接提取NavigationExtras里的状态存入独立的Store切片,更直观可控。
步骤1:定义设置导航状态的Action
import { createAction, props } from '@ngrx/store'; // 定义Action,用于将NavigationExtras的state存入Store export const setNavigationExtraState = createAction( '[Router] Set Navigation Extra State', props<{ state: any }>() );
步骤2:创建Effect监听导航事件
NgRx的routerNavigationAction会在每次导航时触发,它的payload里包含了完整的导航事件,其中就有我们需要的navigationExtras:
import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { routerNavigationAction } from '@ngrx/router-store'; import { map } from 'rxjs/operators'; import { setNavigationExtraState } from './your-actions-file'; @Injectable() export class RouterEffects { captureNavigationState$ = createEffect(() => this.actions$.pipe( ofType(routerNavigationAction), map(action => { // 从导航事件中提取NavigationExtras的state const navExtraState = action.payload.event.navigationExtras.state; return setNavigationExtraState({ state: navExtraState }); }) ) ); constructor(private actions$: Actions) {} }
步骤3:编写Reducer处理Action
在Reducer里创建一个专门的切片来存储导航状态:
import { createReducer, on } from '@ngrx/store'; import { setNavigationExtraState } from './your-actions-file'; // 定义导航状态的接口 export interface NavigationExtraState { data: any | null; } const initialState: NavigationExtraState = { data: null }; export const navigationExtraReducer = createReducer( initialState, on(setNavigationExtraState, (state, { state: navState }) => ({ ...state, data: navState })) );
最后别忘了把这个Reducer加入到你的Store模块里,之后你就可以在任何组件/服务中通过Selector获取这个导航状态了。
方案二:修改RouterStateSerializer,缓存最新NavigationExtras
如果你希望把导航状态直接整合到router-store的routerState里,可以通过自定义服务缓存最新的NavigationExtras,再在Serializer中使用。
步骤1:创建导航状态缓存服务
这个服务会监听Angular的导航事件,缓存每次导航的navigationExtras:
import { Injectable } from '@angular/core'; import { Router, RouterNavigationEvent } from '@angular/router'; import { filter } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class NavigationExtraCacheService { private latestNavExtras: any | null = null; constructor(private router: Router) { // 监听RouterNavigationEvent(导航开始时触发),缓存navigationExtras this.router.events .pipe(filter(event => event instanceof RouterNavigationEvent)) .subscribe((event: RouterNavigationEvent) => { this.latestNavExtras = event.navigationExtras.state; }); } getLatestNavState(): any | null { return this.latestNavExtras; } }
步骤2:修改你的RouterStateSerializer
注入缓存服务,用它来获取正确的导航状态,替代history.state:
import { RouterStateSerializer, RouterStateSnapshot } from '@ngrx/router-store'; import { Injectable } from '@angular/core'; import { NavigationExtraCacheService } from './navigation-extra-cache.service'; export interface IRouterStateUrl { url: string; params: any; state: any; } @Injectable() export class AppRouterStateSerializer implements RouterStateSerializer<IRouterStateUrl> { constructor(private navCacheService: NavigationExtraCacheService) {} serialize(routerState: RouterStateSnapshot): IRouterStateUrl { const { url } = routerState; const params = routerState.root.firstChild ? routerState.root.firstChild.params : {}; // 从缓存服务获取当前导航的state const state = this.navCacheService.getLatestNavState(); return { url, params, state }; } }
步骤3:确保Serializer正确配置
在你的Store模块中,确保StoreRouterConnectingModule使用了这个自定义Serializer:
import { StoreRouterConnectingModule } from '@ngrx/router-store'; import { AppRouterStateSerializer } from './app-router-state-serializer'; @NgModule({ imports: [ // ...其他模块 StoreRouterConnectingModule.forRoot({ serializer: AppRouterStateSerializer }) ] }) export class AppStoreModule {}
这样修改后,router-store中的routerState就会包含当前导航的NavigationExtras状态了。
内容的提问来源于stack exchange,提问作者daddy kom

