For some reason all of my selectors are returning the entire state object instead of the sub states that I thought they should. For example, I am trying to just return the customer State from reducers/customer.ts but instead I get an object with the entire State from index.ts.
I choose the particular structure below after examining the ngrx example app from github, clearly I am doing something(s) wrong.
Here is 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
And 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;
And 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
};
And imports in app.module.ts:
imports: [
...
StoreModule.forRoot(reducers)
],
And lastly how I am am wiring it up in a component and using selector:
...
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);
}
Any help would be appreciated, thanks!
Try using createFeatureSelector inside reducers/index.ts
to start from a top level feature state:
export const getAppState = createFeatureSelector<State>('wholeApp');
Then use it in a different selector to access your customer reducer:
export const getCustomer = createSelector(
getAppState,
(state: State) => state.selectedCustomer
);
From there you can keep going deeper into your state by chaining selectors, as example, if your component just needed to know about a customer's email adresse, it could just subscribe to this:
export const getEmail = createSelector(
getCustomer,
(state: fromCustomer.State) => state.email
);
For more details (and examples) I recommend checking this great article by Todd Motto:
https://ultimatecourses.com/blog/ngrx-store-understanding-state-selectors