Angular Router在NgRx Effect中使用是否受限?导航不生效问题咨询
回答
其实Angular Router在NgRx Effect里使用本身没有硬性限制,但你的写法存在一个常见的上下文问题,导致导航没生效:
- 异步流的变更检测捕获问题:你在
map操作符的回调里直接调用this.router.navigateByUrl('/'),这个操作是在Observable的异步回调中执行的,可能没有被Angular的Zone正确捕获,导致变更检测没有触发,页面也就没有更新。
下面是几种可行的解决方法,按推荐程度排序:
方法1:使用NgRx Router Store(最推荐)
如果你的项目已经集成了@ngrx/router-store,直接派发导航Action是最贴合NgRx理念的做法,导航会和状态流完全同步:
// 注意:不同NgRx版本的导航Action导入方式可能不同,新版本可从@ngrx/router-store导入RouterActions import { go } from '@ngrx/router-store'; // 替换map操作符中的导航代码 map((data: TokenData) => { const user: User = { token: data.token, username: 'dummy', }; console.log(data); // 派发导航Action this.store.dispatch(go(['/'])); return new authenticationActions.AuthenticateSuccessAction(user); })
方法2:手动将导航放入Angular Zone执行
如果暂时不想集成Router Store,可以通过NgZone确保导航操作在Angular的变更检测周期内执行:
首先在Effect的构造函数中注入NgZone:
constructor( private actions$: Actions, private authenticationService: AuthenticationService, private router: Router, private zone: NgZone // 注入NgZone ) {}
然后修改导航代码:
this.zone.run(() => { this.router.navigateByUrl('/'); });
方法3:将导航转换为Observable流
把导航操作包装成Observable,通过concatMap组合进现有流中,确保导航成为异步流的一部分:
.switchMap((action: AuthenticateAction) => this.authenticationService.authenticate(action.payload) .concatMap((data: TokenData) => { const user: User = { token: data.token, username: 'dummy', }; console.log(data); // 将导航Promise转为Observable,再映射成成功Action return Observable.fromPromise(this.router.navigateByUrl('/')) .map(() => new authenticationActions.AuthenticateSuccessAction(user)); }) .catch(error => { console.log(error); return Observable.throw(error); }) );
另外还要排查几个常见的非代码问题:
- 确认路由配置中存在
/路径对应的组件 - 检查是否有路由守卫(如
CanActivate)阻止了导航 - 观察浏览器地址栏是否变化:如果地址栏更新但页面未刷新,基本可以确定是变更检测未触发,用方法2就能解决
内容的提问来源于stack exchange,提问作者rbasniak
相关产品推荐
相关产品推荐

