Redux Spread Operator vs Map - PullRequest
       7

Redux Spread Operator vs Map

4 голосов
/ 22 января 2020

У меня есть состояние объектов в массиве (в моем 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
    };

У меня есть действие, чтобы добавить 1 к количеству объекта, например, {id: 1, di sh: Цыпленок генералов, цена: 10,76, количество: 0} при нажатии кнопки в Cart.jsx. Вот первый редуктор, который я попытался использовать с помощью оператора спреда:

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 }
    ]
  };

Это не сработало, вместо добавления 1 к количеству добавился еще один объект с количеством, установленным в 2.. Итак, я попытался использовать карту, как это

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

И это работало правильно. Мой вопрос: почему не работает оператор спреда? Насколько я могу судить, он должен делать то же самое, что и карта?

Ответы [ 3 ]

4 голосов
/ 22 января 2020

Два куска кода совершенно разные.

Первый создает новый массив из state.addedItems и новый объект { ...existing_item, quantity: existing_item.quantity + 1 }, а затем назначает этот массив свойству addedItems состояния.

Второй кусок кода повторяется addedItems, и если он находит элемент с тем же идентификатором, что и полезная нагрузка, он создает новый объект { ...item, quantity: item.quantity + 1 } и возвращает его вместо исходного элемента из массива.

Таким образом, хотя оба подхода создают новый массив, у первого есть дополнительный объект по сравнению с оригиналом, а у второго - объект с измененным свойством.

2 голосов
/ 22 января 2020

Синтаксис распространения при использовании в литеральном контексте массива не воспроизводит ключи (индексы), а только значения. В отличие от синтаксиса распространения в литеральном контексте объекта, который создает пары ключ / значение. Последний позволяет отменять предыдущие записи новой записью, имеющей тот же ключ, но первый не имеет такого поведения: он всегда распространяет все значения без учета индексов.

При замене элемента в массиве при копировании необходимо:

  • знать индекс, по которому следует выполнить подстановку, и
  • убедиться, что копия является экземпляром массива, а не просто простой объект

Вы можете использовать findIndex и Object.assign([], ) для удовлетворения этих потребностей:

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 }
    })
  }
2 голосов
/ 22 января 2020

Это потому, что в вашем примере распространения нет способа определить, какой объект следует перезаписать. Так что он работает не так, как некоторые другие примеры, которые вы можете увидеть. Рассмотрим следующее:

Если бы у вас был такой объект:

let test = { a: 'first', b: 'second' }

Тогда распространение, как это будет работать:

let newTest = {...test, b: 'third' }

Причина в том, что вы указываете что b должно быть перезаписано.

Когда вы пытаетесь создать тот же эффект с массивом объектов, вы не можете указать ключ. Итак, на самом деле вы просто добавляете новый объект в конец массива.

В примере карты вы проверяете содержимое объекта и возвращаете другой объект, основываясь на том, соответствует ли он вашим условиям, так что вы знаете, какой объект перезаписать.

...