javascriptreactjsdictionaryreact-reduxspread-syntax

Redux Spread Operator vs Map


I have a State of objects in an Array (in my Redux Reducer).

const initialState = {
      items: [
        { id: 1, dish: "General Chicken", price: 12.1, quantity: 0 },
       { id: 2, dish: "Chicken & Broccoli", price: 10.76, quantity: 0 },
        { id: 3, dish: "Mandaran Combination", price: 15.25, quantity: 0 },
        { id: 4, dish: "Szechuan Chicken", price: 9.5, quantity: 0 }
      ],
      addedItems: [],
     total: 0
    };

I have an action to add 1 to the quantity of an object, such as {id:1, dish: Generals Chicken, price: 10.76, quantity:0} when a button in clicked in Cart.jsx. Here's the first Reducer I tried using the spread operator:

case "ADD_QUANTITY":
  let existing_item = state.addedItems.find(
    item => action.payload === item.id
  );

  return {
    ...state,
    addedItems: [
      ...state.addedItems,
      { ...existing_item, quantity: existing_item.quantity + 1 }
    ]
  };

This didn't work, instead of adding 1 to the quantity, it added another object with the quantity set to 2. . .So, I tried using Map like this

case "ADD_QUANTITY":
  return {
    ...state,
    addedItems: state.addedItems.map(item =>
      item.id === action.payload
        ? { ...item, quantity: item.quantity + 1 }
        : item
    )
  };

And this worked correctly. My question is, why didn't the spread operator work? As far as I can tell, it should do the same thing as the Map?


Solution

  • The spread syntax, when used in an array literal context, does not reproduce the keys (the indexes), but just the values. As opposed to the spread syntax in an object literal context, which produces key/value pairs. The latter allows previous entries to be overruled by a new entry, having the same key, but the first does not have this behaviour: it always spreads all values without regards for indexes.

    When replacing an element in an array, while copying it, you need to:

    You can use findIndex and Object.assign([], ) for addressing those needs:

    case "ADD_QUANTITY":
      let index = state.addedItems.findIndex(
        item => action.payload === item.id
      );
      existing_item = state.addedItems[index];
    
      return {
        ...state,
        addedItems: Object.assign([], state.addedItems, {
          [index]: { ...existing_item, quantity: existing_item.quantity + 1 }
        })
      }