首页 > 解决方案 > 尽管使用扩展运算符制作状态副本,但 Redux 状态突变

问题描述

为什么在使用扩展运算符制作对象副本时会收到状态突变警报?我正在尝试用 redux 制作购物车。当添加一个元素或减少它的数量时,我调度一个更新状态的动作。在我的减速器中,如果尚未添加产品,我将返回状态数组的新副本和新对象。如果它已被添加,我将使用 map (返回一个新数组)和我正在增加且其qty属性增加的产品副本进行迭代。 问题出在这个属性上 在不改变状态的情况下更新这个属性的正确方法是什么?

减速器

case types.ADD_TO_CART_SUCCESS:
  const isAdded = state.cart.find(item => item.sku === action.product.sku);
  if (!isAdded) action.product.qty = 1;
  return {
    ...state,
    cart: !isAdded
      ? [action.product, ...state.cart]
      : state.cart.map(item =>
          item.sku === action.product.sku
            ? { ...item, qty: ++item.qty }
            : item
        ),
  };

违规警告

Invariant Violation: A state mutation was detected inside a dispatch, in the path: `user.cart.0.qty`. Take a look at the reducer(s) handling the action {"type":"ADD_TO_CART_SUCCESS"....}

标签: javascriptreactjsreduxdeep-copy

解决方案


正在改变当前项目。前/后递增/递减将改变它操作的当前对象引用。

case types.ADD_TO_CART_SUCCESS:
  const isAdded = state.cart.find(item => item.sku === action.product.sku);
  if (!isAdded) action.product.qty = 1;
  return {
    ...state,
    cart: !isAdded
      ? [action.product, ...state.cart]
      : state.cart.map(item =>
          item.sku === action.product.sku
            ? { ...item, qty: ++item.qty } // <-- This mutates the current item.qty
            : item
        ),
  };

但是,您可以返回一个递增的值,当前item.qty + 1

case types.ADD_TO_CART_SUCCESS:
  const isAdded = state.cart.find(item => item.sku === action.product.sku);
  if (!isAdded) action.product.qty = 1;
  return {
    ...state,
    cart: !isAdded
      ? [action.product, ...state.cart]
      : state.cart.map(item =>
          item.sku === action.product.sku
            ? { ...item, qty: item.qty + 1 }
            : item
        ),
  };

我怀疑您的代码按预期运行,因为您确实正确替换了整个购物车数组,并且您变异的项目是您想要更新的项目,但这表明您的减速器可能不是纯函数,即之前的状态应该仍然在reducer计算下一个状态,在所有方面都等于前一个状态。


推荐阅读