Amruta
Amruta

Reputation: 1565

How to use NgRx 8 actions with NgRx 7 reducer

I'm using the NgRx library in my new Angular 8 project. I've been told that they create the actions using createAction i.e. NgRx 8 but they create the reducers using NgRx 7. I was given a task in which I used NgRx 8 for my reducer which I now have to change to NgRx 7. My actions and reducer are as below:

book.actions.ts

import { createAction, props } from "@ngrx/store";
import { Book } from "./book";

export const BeginGetBooksAction = createAction("BeginGetBooks");

export const SuccessGetBooksAction = createAction(
  "SuccessGetBooks",
  props<{ payload: Book[] }>()
);

export const BeginAddBookAction = createAction(
  "BeginAddBook",
  props<{ payload: Book }>()
);

export const SuccessAddBookAction = createAction(
  "SuccessAddBook",
  props<{ payload: Book[] }>()
);

book.reducer.ts

import { Action, createReducer, on } from "@ngrx/store";
import * as BooksActions from "./book.action";
import { Book } from "./book";

export interface BooksState {
  Books: Book[];
  ReadBooks: { book: Book; addedOn: Date }[];
  WantToReadBooks: { book: Book; addedOn: Date }[];
  editBook: Book;
}

const initialState: BooksState = {
  Books: [],
  ReadBooks: [],
  WantToReadBooks: [],
  editBook: new Book()
};

export function booksReducer(state = initialState, action: Action) {
  switch (action.type) {
    case BooksActions.BeginGetBooksAction.type:
      return state;

    case BooksActions.SuccessGetBooksAction.type:
      return { ...state, Books: action.payload };

    case BooksActions.BeginAddBookAction.type:
        return state;

    case BooksActions.SuccessAddBookAction.type:
        return { ...state, Books: action.payload };

    default:
      return state;
  }
}

I get an error for action.payload

Property 'payload' does not exist on type 'Action'.

Can someone tell me what I am doing wrong???

Upvotes: 2

Views: 970

Answers (2)

timdeschryver
timdeschryver

Reputation: 15487

I wrote down a comparison in NgRx creator functions 101.

In the article you can see how you can combine the syntax of both versions:

export const addToCart = createAction(
  // action's type
  '[Product List] Add to cart',
  // optional payload
  props<{ sku: string }>(),
)
export const removeFromCart = createAction(
  '[Product List] Remove from cart',
  props<{ sku: string }>(),
)

export function reducer(
  state = initialState,
  action: ReturnType<typeof addToCart> | ReturnType<typeof removeFromCart>,
) {
  switch (action.type) {
    case addToCart.type:
      return {
        ...state,
        cartItems: {
          ...state.cartItems,
          [action.sku]: (state.cartItems[action.sku] || 0) + 1,
        },
      }

    case removeFromCart.type:
      return {
        ...state,
        cartItems: {
          ...state.cartItems,
          [action.sku]: Math.max((state.cartItems[action.sku] || 0) - 1, 0),
        },
      }

    default:
      return state
  }
}

Upvotes: 5

Anarno
Anarno

Reputation: 1640

Your reducer is good, just your type definition is the problem. You use a plain Action type where payload doesn't exists. Try another type definition, like any or try union types, but when you try union types, you need all named imports from the action file. I think the best solution for you is the next generation syntax of reducer, try use the new format.

Upvotes: 0

Related Questions