使用 @ngrx/entity 处理商店中的集合,getSelectors() 不起作用

Posted

技术标签:

【中文标题】使用 @ngrx/entity 处理商店中的集合,getSelectors() 不起作用【英文标题】:Using @ngrx/entity for handling collections in store, getSelectors() not working 【发布时间】:2018-10-02 14:56:41 【问题描述】:

我正在尝试使用 @ngrx/entity lib 实现 NgRx 存储,但我无法使用 @ngrx/entity getSelectors 检索任何数据。 Redux Devtools 将 Effect() 加载的我的集合正确地显示为实体。所以我的效果工作正常。现在我想通过使用来自adapter.getSelectors() 函数的selectAll 选择器来选择数据作为数组。我的 reducer 索引如下所示

reducers/index.ts

import  ActionReducerMap, createFeatureSelector, createSelector  from '@ngrx/store';

import * as fromModels from './models.reducer';
import  EntityState  from '@ngrx/entity';

export interface State 
  models: fromModels.State;


export const reducers: ActionReducerMap<State> = 
  models: fromModels.reducer
;

export const getModelsState = createFeatureSelector<fromModels.State>('models');
export const  selectAll: getAllModels  = fromModels.adapter.getSelectors(getModelsState);

reducers/models.reducer.ts

import  createFeatureSelector, createSelector  from '@ngrx/store';
import  createEntityAdapter, EntityState, EntityAdapter  from '@ngrx/entity';

import  ModelsActions, ModelsActionTypes  from '../actions';
import  Model  from '../../models/model';

export const adapter: EntityAdapter<Model> = createEntityAdapter<Model>(
  selectId: model => model.id,
  sortComparer: (modelA, modelB) => modelA.id === modelB.id ? 0 : (modelA.id === modelB.id ? 1 : -1)
);

export interface State extends EntityState<Model> 
const initialState = adapter.getInitialState();

export function reducer(state = initialState, action: ModelsActions): State 
  switch (action.type) 

    case ModelsActionTypes.LoadSuccess:
      return adapter.addAll(action.payload, state);

    default: return state;
  

在我的容器组件中,我想通过 ngrx/entity 选择器选择数据并使用异步管道显示数据。 (我缩小了模板)

models.component.ts

// All other import statements
import  Store, select  from '@ngrx/store';
import * as fromFeature from '../store';

@Component(
  template: `models$ | async | json`
)
export class ModelsComponent implements OnInit 
  models$: Observable<Model[]>;

  constructor(private store: Store<fromFeature.State>) 

  ngOnInit() 
    this.models$ = this.store.select(fromFeature.getAllModels);
    this.store.dispatch(new fromFeature.LoadModels());
  

控制台打印错误

ModelsComponent.html:2
ERROR TypeError: Cannot read property 'ids' of undefined
at selectIds (entity.es5.js:45)
at eval (store.es5.js:572)

有解决这个问题的建议或想法吗?谢谢!

更新 [请求的模板]

模板只订阅models$ observable,与reduce模板中的相同。 model-card.component.ts 只获取 Input() 和 ng-content

<app-model-card
  *ngFor="let model of models$ | async"
  [logo]="model.id"
  [routerLink]="[model.id]">
  model.title
</app-model-card>

更新 [请求的操作]

actions/models.action.ts

import  Action  from '@ngrx/store';
import  Model  from '../../models/model';

export enum ModelsActionTypes 
  Load = '[Models] Load',
  LoadSuccess = '[Models] Load Success',
  LoadFailed = '[Models] Load Failed'


export class LoadModels implements Action 
  readonly type = ModelsActionTypes.Load;


export class LoadModelsSuccess implements Action 
  readonly type = ModelsActionTypes.LoadSuccess;

  constructor(public payload: Model[]) 


export class LoadModelsFailed implements Action 
  readonly type = ModelsActionTypes.LoadFailed;

  constructor(public payload: any) 


export type ModelsActions =
  LoadModels |
  LoadModelsSuccess |
  LoadModelsFailed;

models.effects.ts

import  Injectable  from '@angular/core';
import  Actions, Effect  from '@ngrx/effects';
import  Observable  from 'rxjs/Observable';
import  of  from 'rxjs/observable/of';
import  map, switchMap, catchError  from 'rxjs/operators';

import  ModelsActionTypes, LoadModelsSuccess, LoadModelsFailed  from 
  '../actions';
import  ModelsService  from '../../services/models.service';

@Injectable()
export class ModelsEffects 
  constructor(
    private actions$: Actions,
    private modelsService: ModelsService
  ) 

  @Effect()
  loadModels$ = this.actions$
    .ofType(ModelsActionTypes.Load)
    .pipe(
      switchMap(() => 
        return this.modelsService.getModels().pipe(
          map(models => new LoadModelsSuccess(models)),
          catchError(error => of(new LoadModelsFailed(error)))
        );
      )
    );

【问题讨论】:

请提供ModelsComponent.html的内容。 @DiabolicWords 更新了我的问题附加模板。无法想象错误在模板中。缩小的模板会导致同样的错误。 可能是this.models$ = this.store.select(fromFeature.getAllModels) -> this.models$ = this.store.select(fromFeature.selectAll)? @RichardMatsen 不起作用,同样的错误。 我注意到'./models.reducer'reducers/model.reducers.ts - 但这肯定是问题中的错字,对吧? 【参考方案1】:

哦,该死的,我想通了。问题是createFeatureSelector,它只是选择功能(正如它的名字所说)。我将模块注册为StoreModule.forFeature('configuration', reducers)

然后解决方案是从功能选择器中获取 ConfigurationState,从默认选择器中获取模型状态。

reducers/index.ts

[...]
export const getConfigurationState = createFeatureSelector<ConfigurationState>('configuration');
export const getModelsState = createSelector(
  getConfigurationState,
  (configuration) => configuration.models
);

export const 
  selectIds,
  selectEntities,
  selectAll
 = fromModels.adapter.getSelectors(getModelsState);

感谢您的帮助!

【讨论】:

我这样做了,但仍然遇到同样的错误。有什么解决办法吗? 需要有关您的问题和代码的更多信息,此解决方案适用于我。创建一个问题或 stackblitz 让我知道。 我想通了,我的状态界面有问题,因此无法选择所需的状态。谢谢。

以上是关于使用 @ngrx/entity 处理商店中的集合,getSelectors() 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

[NgRx] NgRx Entity Adapter Configuration - Understanding sortComparer and selectId

NgRX实体:ID在州内未定义

如何一次过滤 mat 表数据源和相关的异步属性?

typescript 可用于商店参考数据的简单代码,用于使用knockout.js处理Web应用程序中的列表。

Magento 2:如何按商店ID过滤产品集合

使用同一文档中的字段减少mongodb中的字段