NgRx selector返回Store对象:定义action、reducer、selector后无法获取预期数据
问题原因&解决方法
store.pipe(select(selectReceipts))返回的是冷Observable,不会直接返回数据,必须订阅或者配合Angular的async管道使用才会触发取值逻辑,直接打印只会拿到Observable对象本身。- 你调用
dispatch(getReceipts([]))时传入了空数组,结合你当前reducer的逻辑,会直接把store里的receipts数据覆盖为空数组,即使后续取值也拿不到有效数据。 - 需确认reducer已正确注册到Store模块,且注册时的key和selector里取值的
state.receipts完全一致,否则selector会取不到对应状态。
修正后的代码示例
1. 组件代码
import { Component, OnInit, OnDestroy } from '@angular/core'; import { Observable, Subject, takeUntil } from 'rxjs'; import { Store, select } from '@ngrx/store'; import { getReceipts } from './file-state.actions'; import { selectReceipts } from './file-state.selector'; export class ViewFilesComponent implements OnInit, OnDestroy { // 直接声明存储Observable,模板可配合async管道直接使用 receipts$: Observable<Receipt[]> = this.store.pipe(select(selectReceipts)); // 用于自动取消订阅,避免内存泄漏 private destroy$ = new Subject<void>(); constructor(private store: Store<AppState>) {} ngOnInit(): void { // 若需要在TS代码中获取数据,手动订阅 this.receipts$ .pipe(takeUntil(this.destroy$)) .subscribe(receipts => { console.log('获取到的收据数据:', receipts); }); // 测试dispatch,传入有效测试数据,不要传空数组 this.store.dispatch(getReceipts([ { merchant_name: '连锁超市' }, { merchant_name: '沿街餐厅' } ])); } ngOnDestroy(): void { // 组件销毁时终止订阅 this.destroy$.next(); this.destroy$.complete(); } }
如果要在模板中直接渲染,不需要手动订阅,直接用async管道即可:
<ul> <li *ngFor="let receipt of receipts$ | async"> 商家名称:{{receipt.merchant_name}} </li> </ul>
2. 检查Store模块注册
确认根模块或特性模块中已正确注册reducer,key必须和selector取值的receipts对应:
// app.module.ts 根模块注册示例 import { NgModule } from '@angular/core'; import { StoreModule } from '@ngrx/store'; import { receiptReducer } from './file-state.reducers'; @NgModule({ imports: [ // 其他模块导入 StoreModule.forRoot({ receipts: receiptReducer }) ] }) export class AppModule {}
补充说明
你当前的实现是同步更新收据列表的逻辑,如果需要从后端接口请求收据数据,还需要配置NgRx Effect处理异步请求,再触发action更新store。如果需要保留原有收据列表而非全量替换,可以把reducer的返回值修改为[...state, ...receipts]。
内容的提问来源于stack exchange,提问作者Peter Boomsma
相关产品推荐
相关产品推荐

