如何使用Route Resolver正确解析NgRx Store存储数据
使用Route Resolver从NgRx Store获取数据返回null的解决方案
问题根因
你遇到的返回null问题本质是两个原因叠加导致的:
first()、take(1)这类操作符只会返回订阅生效后收到的第一个值,不会等待后续状态变更- 浏览器刷新时NgRx Store的内存状态会完全重置,初始状态下
customer字段默认是null,操作符拿到这个初始null值就会直接完成流,不会等待后续数据加载完成
你找到的参考方案只适用于「进入路由前Store中已经存在目标数据」的场景,没有覆盖刷新后需要重新拉取数据的情况,所以本地测试刷新时会拿到null。
正确实现逻辑
Route Resolver解析Store数据时不能直接取值,需要按以下流程处理:
- 先读取当前Store中是否存在有效的客户数据
- 如果数据不存在,先派发加载客户数据的Action,触发对应Effect发起接口请求
- 持续监听Store状态,过滤掉null的初始值,等数据加载完成(状态变为非null有效值)后,再取第一个值返回,完成路由解析
完整实现代码
import { Injectable } from '@angular/core'; import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { Store } from '@ngrx/store'; import { of, Observable } from 'rxjs'; import { take, switchMap, filter, first } from 'rxjs/operators'; import { AppState } from 'src/app/store/app.state'; // 替换成你项目中实际的action、selector路径 import { loadActiveCustomer } from 'src/app/store/customer/customer.actions'; import { selectActiveCustomer } from 'src/app/store/customer/customer.selectors'; @Injectable({ providedIn: 'root' }) export class GetActiveCustomerService implements Resolve<any> { constructor(private store: Store<AppState>) {} resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> { return this.store.select(selectActiveCustomer).pipe( take(1), switchMap(existingCustomer => { // 已有有效数据直接返回 if (existingCustomer) { return of(existingCustomer); } // 无数据时先触发加载 this.store.dispatch(loadActiveCustomer()); // 等待数据加载完成,过滤空值后返回第一个有效结果 return this.store.select(selectActiveCustomer).pipe( filter(customer => !!customer), first() ); }) ); } }
注意事项
- 建议使用专门的selector(比如示例中的
selectActiveCustomer)获取Store状态片段,不要直接用store.select('customer')这种字符串写法,避免状态字段名拼写错误导致一直取到null - 需要在Customer对应的Effect中监听
loadActiveCustomer动作,发起接口请求拿到客户数据后,派发成功动作将数据写入Store,否则filter会一直等不到有效值导致路由卡住 - 如果做了Store持久化(把状态存在localStorage/sessionStorage),需要在应用初始化阶段(通过
APP_INITIALIZER)就把持久化数据写入Store,避免初始状态为空
内容的提问来源于stack exchange,提问作者Mario
相关产品推荐
相关产品推荐

