使用@ngrx/entity处理Store集合时getSelectors()无法正常工作
我来帮你一步步排查这个问题,毕竟我之前在使用@ngrx/entity时也踩过类似的坑😉。既然Redux Devtools已经显示entities正确生成了,那问题大概率出在selector的配置或者使用环节,我们逐个排查:
1. 先确认Feature Selector的Key是否匹配
首先要检查你用createFeatureSelector定义的feature key,和你在StoreModule.forFeature()里注册的key是不是完全一致。比如如果你的模块注册代码是这样的:
@NgModule({ imports: [ StoreModule.forFeature('products', productsReducer) ] })
那你的feature selector必须严格对应这个key:
// 正确写法,key和注册的'products'一致 const selectProductsState = createFeatureSelector<ProductsState>('products'); // ❌错误写法:key不匹配的话,selector根本找不到对应的state片段 const selectProductsState = createFeatureSelector<ProductsState>('product');
2. 检查State结构是否符合@ngrx/entity要求
@ngrx/entity的state必须包含ids(数组)和entities(对象)这两个核心属性,如果你还有额外的状态(比如loading、error),需要让你的state接口继承EntityState:
import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity'; import { Product } from './product.model'; // 定义符合entity要求的state接口 export interface ProductsState extends EntityState<Product> { loaded: boolean; loading: boolean; error: string | null; } // 创建entity adapter并初始化state export const adapter: EntityAdapter<Product> = createEntityAdapter<Product>(); export const initialState: ProductsState = adapter.getInitialState({ loaded: false, loading: false, error: null });
同时要确保你的reducer处理action时,都是用adapter提供的方法(比如addAll、addOne)来更新state,而不是手动修改ids和entities。
3. 正确组合adapter.getSelectors()与Feature Selector
这是最容易出错的环节:adapter.getSelectors()需要传入一个能返回对应entity state片段的selector,而不是直接传入root state。正确的写法应该是:
import { createFeatureSelector, createSelector } from '@ngrx/store'; import { adapter, ProductsState } from './products.reducer'; // 第一步:获取整个feature的state const selectProductsState = createFeatureSelector<ProductsState>('products'); // 第二步:传入这个selector给getSelectors,拿到所有实体选择器 const { selectAll, // 返回所有实体的数组 selectEntities, // 返回实体对象(key是id,value是实体) selectIds, // 返回所有实体id的数组 selectTotal // 返回实体总数 } = adapter.getSelectors(selectProductsState); // 第三步:可以封装成公共selector供组件使用 export const selectAllProducts = selectAll;
如果直接把root state传给getSelectors(),它找不到ids和entities,自然返回空数组。
4. 组件中正确调用Selector
最后检查组件里的使用方式,确保用store.select()订阅正确的selector,并配合async管道使用:
import { Component, OnInit } from '@angular/core'; import { Store } from '@ngrx/store'; import { selectAllProducts } from './state/products.selectors'; import { Observable } from 'rxjs'; import { Product } from './product.model'; @Component({ template: ` <div *ngFor="let product of products$ | async"> {{ product.name }} </div> ` }) export class ProductsComponent implements OnInit { products$: Observable<Product[]>; constructor(private store: Store) {} ngOnInit() { this.products$ = this.store.select(selectAllProducts); // 别忘了触发加载action哦! this.store.dispatch(loadProducts()); } }
按照上面的步骤排查下来,应该就能解决你用selectAll获取不到数据的问题了。
内容的提问来源于stack exchange,提问作者Felix Lemke

