如何在NgRx中从Router_Cancel事件获取之前的路由状态?
NgRx + CanDeactivate守卫:取消导航后路由状态未同步的解决方案
嘿,我刚好碰到过和你一模一样的问题!咱们来一步步解决它:
问题根源
当你触发导航时,NgRx的路由模块会先派发Router_Navigation事件更新Store状态,不管后续CanDeactivate守卫是否允许导航。如果守卫阻止了导航,虽然Router_Cancel事件会触发,但默认情况下NgRx不会自动把路由状态回滚到之前的页面,这就是问题所在。
解决方案步骤
创建一个处理路由取消的Effect
我们需要监听Router_Cancel事件,手动把Store里的路由状态恢复到导航前的状态:import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { RouterCancelAction, ROUTER_CANCEL } from '@ngrx/router-store'; import { tap } from 'rxjs/operators'; import { Store } from '@ngrx/store'; import { routerNavigatedAction } from '@ngrx/router-store'; @Injectable() export class RouterEffects { restoreRouteOnCancel$ = createEffect(() => this.actions$.pipe( ofType<RouterCancelAction>(ROUTER_CANCEL), tap((action) => { // 从取消事件中获取导航前的原始路由状态 const previousRouterState = action.payload.routerState; // 派发routerNavigatedAction来重置路由状态 this.store.dispatch(routerNavigatedAction({ routerState: previousRouterState, event: action.payload.event, url: action.payload.event.url, navigationId: action.payload.event.id })); }) ), { dispatch: false } // 手动派发了action,所以这里设为false避免重复触发 ); constructor(private actions$: Actions, private store: Store) {} }确保路由状态序列化正确
要保证你的路由状态序列化器能正确处理路由信息,这样恢复状态时才能精准回到导航前的页面。如果有自定义序列化逻辑,要确认previousRouterState能被正确解析。验证守卫逻辑
确认你的CanDeactivate守卫在需要阻止导航时,正确返回false或者Observable<false>,这样Router_Cancel事件才会被NgRx正确触发。
额外说明
你在NgRx文档里看到的ROUTER_CAN_DEACTIVATE,主要是用来让你在CanDeactivate守卫中访问Store的状态,和我们现在要解决的状态回滚问题没有直接关联。上面的方案是目前处理这类问题最直接有效的方式。
内容的提问来源于stack exchange,提问作者kumar
相关产品推荐
相关产品推荐

