ngrx 4 选择器返回整个状态而不是子状态

Posted

技术标签:

【中文标题】ngrx 4 选择器返回整个状态而不是子状态【英文标题】:ngrx 4 selectors returning entire state instead of sub states 【发布时间】:2018-07-06 10:21:15 【问题描述】:

出于某种原因,我的所有选择器都返回了整个状态对象,而不是我认为应该返回的子状态。例如,我试图从 reducers/customer.ts 返回客户状态,但我从 index.ts 中获取了一个包含整个状态的对象。

在检查了 github 上的 ngrx 示例应用程序后,我选择了下面的特定结构,显然我做错了什么。

文件结构:

这是actions/customer.ts:

import  Action  from '@ngrx/store';
import  State  from '../reducers/customer';

export enum CustomerActionTypes 
  Add = '[Customer] Add Selected Customer to Store'


export class Add implements Action 
  readonly type = CustomerActionTypes.Add;
  constructor(public payload: State) 
    console.log("from action: " + JSON.stringify(payload,null,2));
  


export type CustomerActions = Add

还有reducers/customer.ts:

import  ActionReducer, Action  from '@ngrx/store';
import  CustomerActionTypes, CustomerActions  from '../actions/customer';

export interface State 
  name: string;
  status: string;
  phone: string;
  stage: string;
  type: string;
  id: string;
  street: string;
  city: string;
  postalCode: string;
  email: string;
  state: string;


export function reducer(
  state: State,
  action: CustomerActions
): State 
  switch (action.type) 
    case CustomerActionTypes.Add:
      return action.payload

    default:
      return state;
  


export const getCustomerState = (state: State) => state;

还有reducers/index.ts:

//For reducers map
import * as fromMainNav from './main-nav-ui';
import * as fromTradeUI from './trade-ui';
import * as fromAppts from './appointments';
import * as fromCustomer from './customer';


//Whole application state
export interface State 
  mainNavUI: fromMainNav.State;
  tradeUI: fromTradeUI.State;
  appointments: fromAppts.State;
  selectedCustomer: fromCustomer.State;


//Reducer map
export const reducers = 
  mainNavUI: fromMainNav.reducer,
  tradeUI: fromTradeUI.reducer,
  appointments: fromAppts.reducer,
  selectedCustomer: fromCustomer.reducer
;

并在 app.module.ts 中导入:

imports: [
    ...
    StoreModule.forRoot(reducers)
  ],

最后我是如何将它连接到一个组件中并使用选择器的:

...
import * as fromCustomer from '../../../shared/state/reducers/customer';
...

public cust$: Observable<fromCustomer.State>;

constructor(
    ...
    public ngrxStore: Store<fromCustomer.State>
  ) 
      this.cust$ = ngrxStore.select(fromCustomer.getCustomerState);
    

任何帮助将不胜感激,谢谢!

【问题讨论】:

【参考方案1】:

尝试在reducers/index.ts 中使用createFeatureSelector 以从***功能状态开始:

export const getAppState = createFeatureSelector<State>('wholeApp');

然后在不同的选择器中使用它来访问您的客户减速器:

export const getCustomer = createSelector(
  getAppState,
  (state: State) => state.selectedCustomer
);

从那里你可以通过链接选择器继续深入你的状态,例如,如果你的组件只需要知道客户的电子邮件地址,它可以订阅这个:

export const getEmail = createSelector(
   getCustomer,
   (state: fromCustomer.State) => state.email
);

有关更多详细信息(和示例),我建议查看 Todd Motto 的这篇精彩文章:

https://ultimatecourses.com/blog/ngrx-store-understanding-state-selectors

【讨论】:

非常感谢,这很有意义。作为一种解决方法,我刚刚将它们全部移入索引,但我更喜欢这种方法。 你能解释一下,'wholeApp'-string 是从哪里来的吗?谢谢。 @EternalBeginner 这是你给你的状态起的名字,它可以是一个像productspizza或只是app这样的模块。我刚刚添加了一篇可以更好地解释它的精彩文章的链接。【参考方案2】:

Salem 为您提供了一个很好的解决方案,但您的问题的根本原因是应用程序组件中的这一行。

this.cust$ = ngrxStore.select(fromCustomer.getCustomerState);

您的 fromCustomer.getCustomerState 定义如下:

export const getCustomerState = (state: State) =&gt; state;

由于 ngrxStore.select 将始终返回根状态,当然您仍将根据您定义此 getCustomerState 函数的方式获取根状态。您的 getCustomerState 函数不进行任何转换,它只返回传递的任何内容通过。

【讨论】:

以上是关于ngrx 4 选择器返回整个状态而不是子状态的主要内容,如果未能解决你的问题,请参考以下文章

Ngrx - 选择器在存储更改后没有发出新值

在单元测试中:如何覆盖由 entityAdapter.getSelectors() 创建的 NGRX 选择器

无法读取未定义(读取“地图”)NGRX 实体的属性

Angular 7、Ngrx、Rxjs 6 - 访问延迟加载模块之间的状态

从使用 NgRx 选择商店获取对象而不是列表

在单元测试中使用参数模拟 ngrx 存储选择器(Angular)