Home > front end >  NgRx selector is returning the Store object
NgRx selector is returning the Store object

Time:11-13

I'm trying to integrate NgRx with my Angular app but I'm having some trouble. I've defined an action, reducer and selector but I'm not getting the data I'm expecting.

I define an action getReceipts:

// file-state.actions.ts

export const getReceipts = createAction(
  '[Receipt] Get receipt',
  (receipts: Receipt[]) => ({ receipts })
);

A reducer receiptReducer, which should be called by the getReceipts action:

// file-state.reducers.ts

const initialState: ReadonlyArray<Receipt> = [
  {merchant_name: 'default'}
];

export const receiptReducer = createReducer(
  initialState,
  on(ReceiptActions.getReceipts, (state, { receipts }) => [...receipts]),
)

And a selector to get the data from the store:

// file-state.selector.ts

export const selectReceipts = createSelector(
  (state: AppState) => state.receipts,
  (receipts: Receipt[]) => receipts
);

And finally in my Angular component:

export class ViewFilesComponent implements OnInit {
  // receipts$: Observable<Receipt[]>;

  constructor(private store: Store<AppState>) {
    console.log(this.store.pipe(select(selectReceipts)))
    console.log(this.store.dispatch(getReceipts([])))
  }

  ngOnInit(): void {}

}

The dispatch is returning an undefined object, which is fine because an action returns void. So I think I need to call the selectReceipts selector, but that returns the Store object:

enter image description here

CodePudding user response:

My advice here below, I would not use an action to get a part of the application state, in your component you can use the observable given by store.select, passing the reducer as argument.

You should use an action, for example, when you need to make an http call. Also the state should be a simple object.

Since my application is composed by several feature modules, I usually use injectionTokens to get a reducer inside a component, I skipped that part in this example.

file: store/reducer/index.reducer.ts

export interface State {
  receipts: Array<Receipt>
}

export const initialState: State = {
  receipts: []
}

const reducerDefinition = createReducer(
  initialState,
  on(fromAction.someAction, (state, { someValue}) => ({
    ...state, 
    someProp: someValue
  }))
)

export function reducer(state, action) {
  return reducerDefinition(state, action)
}

export const getReceipts = (state: State) => state.receipts

In your component you can subscribe to the getReceipts$ observable

this.getReceipts$ = this.store.select(getReceipts)

CodePudding user response:

Piyush's answer helped me the best. I created a class member receipts$ and gave it a Observable of type []. Then in the constructor I passed the returned observable from the NgRx store this.store.pipe(select(selectReceipts) in it. Then in the html I did:

<ul>
  <li *ngFor="let receipt of receipts$ | async; index as i">
    <p>
      {{i}}: {{receipt.merchant_name}}
    </p>
  </li>
</ul>
  • Related