0
votes

I am playing around with ngrx store, deleting, fetching, and editing elements in array works just fine, but the problem is when I first time insert object into an array like {id: 1, name: 'Potato', quantity: 2}, two exactly same objects are inserted unless i filter it like in reducer below.

State

export const initialShoppingState: ShoppingState = {
    shoppingList: [],
};

This one works but probably i shouldn't filter it to prevent adding same object

on(ShoppingAction.shoppingItemAdded, (state, { shoppingItem }) => {
    console.log(state);
    return ({ ...state, shoppingList: [...state.shoppingList.filter((item) => item.id !== shoppingItem.id), shoppingItem] });
}),

This one adds first item two times, next items items only once.

on(ShoppingAction.shoppingItemAdded, (state, { shoppingItem }) => {
    console.log(state);
    return ({ ...state, shoppingList: [...state.shoppingList.concat(shoppingItem)] });
}),
1
probably not the problem, but I think you don't have to use the spread operator when you use .concat because it does return a new array. Why don't you use [...state.shoppingList, shoppingItem] like you do in the filter example - Marcel Hoekstra
Yeah i dont have to use spread operator and brackets and it will go like this: return ({ ...state, shoppingList: state.shoppingList.concat(shoppingItem) }); and it compiles but still when I am adding first object to empty array it is duplicated. What is interesting if I add few entries and then wipe them out so array is again empty, adding works normally - no duplicates - quimak
Could you please make an example in stackblitz.com and update the question with the link? - marianocodes

1 Answers

1
votes

Going from the code, this is the expected behavior and this isn't something the store can solve.

The problem is that you're appending an item to the array. The only solution to this is using the filter as you've done.

If you structure your state as a dictionary, you don't have this problem because the id will be unique. See Normalizing State for more info.

See this for an example.

export const initialState: State = {
  cartItems: {},
};

export function reducer(state = initialState, action: CartActions) {
  switch (action.type) {
    case CartActionTypes.AddToCart:
      return {
        ...state,
        cartItems: {
          ...state.cartItems,
          [action.payload.sku]: (state.cartItems[action.payload.sku] || 0) + 1,
        },
      };

    case CartActionTypes.RemoveFromCart:
      return {
        ...state,
        cartItems: {
          ...state.cartItems,
          [action.payload.sku]: Math.max((state.cartItems[action.payload.sku] || 0) - 1, 0),
        },
      };

    case CartActionTypes.EmptyCart:
      return initialState;

    default:
      return state;
  }
}