Angular组件页面刷新后无法收到服务从sessionStorage加载的推送数据
问题根因
你遇到的问题本质是Subject的特性导致的时序问题:普通Subject只会将订阅之后触发的next()事件推送给订阅者。
如果你的Angular服务是根注入器提供的(默认providedIn: 'root'),服务会在应用初始化阶段就实例化,构造函数会在组件初始化之前执行,此时你已经调用了dataSub.next(this.data)推送了存储的数据,但组件的ngOnInit是在组件渲染阶段才执行,此时才完成订阅,自然收不到之前已经发送过的事件。
解决方案
方案1:替换为BehaviorSubject(最推荐)
BehaviorSubject会缓存最新的推送值,新订阅者订阅时会自动收到缓存的最新值,完美匹配你的场景,只需要修改服务中的Subject定义即可:
// some.service.ts // 替换原来的Subject定义,给个空数组作为初始值 private dataSub = new BehaviorSubject<Data[]>([]); public dataObservable$ = this.dataSub.asObservable(); private data: Data[] = []; constructor() { const data = sessionStorage.getItem("data"); if(data){ this.data = JSON.parse(data); // 此时next的新值会被BehaviorSubject缓存,后续组件订阅就能收到 this.dataSub.next(this.data); } }
你也可以直接将sessionStorage读取的结果作为BehaviorSubject的初始值,简化代码:
private dataSub = new BehaviorSubject<Data[]>( sessionStorage.getItem("data") ? JSON.parse(sessionStorage.getItem("data") as string) : [] );
方案2:使用ReplaySubject
如果你不需要初始值,只需要让新订阅者收到最近一次推送的内容,可以用ReplaySubject,配置为缓存1条历史数据即可:
// some.service.ts private dataSub = new ReplaySubject<Data[]>(1); public dataObservable$ = this.dataSub.asObservable();
方案3:组件订阅时主动拉取当前值
如果你不想改动Subject的类型,可以给服务加一个公开的get方法获取当前的data列表,组件订阅时先主动取一次当前值:
// some.service.ts // 新增get方法 public getCurrentData(): Data[] { return [...this.data]; } // some.component.ts ngOnInit(): void { // 先主动拉取当前最新值 this.data = this.someService.getCurrentData(); // 再订阅后续变更 this.dataSubscription = this.someService.dataObservable$.subscribe(newData => { this.data= newData ; }) }
额外优化建议
记得在组件的ngOnDestroy生命周期中取消订阅,避免内存泄漏:
// some.component.ts ngOnDestroy(): void { this.dataSubscription.unsubscribe(); }
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

