【问题标题】:Redux Spread Operator vs MapRedux 扩展运算符与映射
【发布时间】:2020-05-09 01:26:27
【问题描述】:

我有一个数组中的对象状态(在我的 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,菜:将军鸡,价格:10.76,数量:0} 当在 Cart.jsx 中单击一个按钮时。这是我尝试使用扩展运算符的第一个 Reducer:

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

这工作正常。我的问题是,为什么传播运算符不起作用?据我所知,它应该和 Map 做同样的事情?

【问题讨论】:

    标签: javascript reactjs dictionary react-redux spread


    【解决方案1】:

    这两段代码完全不同。

    第一个从state.addedItems 和新对象{ ...existing_item, quantity: existing_item.quantity + 1 } 创建一个新数组,然后将该数组分配给状态的addedItems 属性。

    第二段代码迭代addedItems,如果找到与有效负载具有相同id的元素,它会创建一个新对象{ ...item, quantity: item.quantity + 1 }并返回该对象,而不是数组中的原始项目。

    因此,尽管这两种方法都创建了一个新数组,但第一种方法与原始方法相比有一个额外的对象,而第二种方法有一个具有修改属性的对象。

    【讨论】:

      【解决方案2】:

      在数组字面量上下文中使用扩展语法时,不会重现键(索引),而只是重现值。与对象文字上下文中的扩展语法相反,它产生键/值对。后者允许以前的条目被具有相同键的新条目推翻,但第一个条目没有这种行为:它总是传播所有值而不考虑索引。

      当替换数组中的一个元素,同时复制它时,你需要:

      • 知道应该执行替换的索引,并且
      • 确保副本是 Array 的实例,而不仅仅是普通对象

      您可以使用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 }
          })
        }
      

      【讨论】:

      • 那么,obj 正在正确更新(使用 spread),但是数组中的元素/obj 不能被覆盖,因为它是一个数组,因此没有找到它的键?
      • 只是扩展语法在对象文字中的含义与在数组文字中的含义不同。是的,在数组文字中,扩展语法只是使用新的增量索引将值 添加 到数组的末尾。在对象传播中,键确定它是真正的新条目,还是已经传播的条目的更新。
      • 另外what可以传播也有区别:在对象传播中,你可以传播一个对象,但是在数组传播中,你必须传播一些可迭代的东西.我提到这一点只是为了强调虽然语法看起来相同,但它们是不同的东西。
      【解决方案3】:

      这是因为在您的传播示例中,它无法告诉它应该覆盖哪个对象。因此,它的运行方式与您可能看到的其他一些示例不同。考虑以下几点:

      如果你有这样的对象:

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

      然后像这样进行传播会起作用:

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

      原因是您指定应覆盖 b。

      当您尝试使用一组对象创建相同的效果时,您无法指定键。所以你实际上所做的只是将新对象附加到数组的末尾。

      在地图示例中,您正在检查对象内容并根据它是否符合您的条件返回一个不同的对象,因此您知道要覆盖哪个对象。

      【讨论】:

      • 优秀的答案。这很容易成为公认的答案。谢谢。
      猜你喜欢
      • 2019-04-11
      • 2019-03-13
      • 2018-07-29
      • 1970-01-01
      • 1970-01-01
      • 2020-04-06
      • 1970-01-01
      • 1970-01-01
      • 2018-04-07
      相关资源
      最近更新 更多