尽管使用传播运算符制作状态副本,但 Redux 状态仍会发生变化

Redux state mutation despite making state copy with spread operator

为什么我在使用扩展运算符制作对象副本时收到状态突变警报? 我正在尝试用 redux 制作购物车。当添加一个元素或减少它的数量时,我会发送一个更新状态的动作。 在我的减速器中,如果尚未添加产品,我 return 带有新对象的状态数组的新副本。如果它已经添加,我将使用 map(returns 一个新数组)和我正在增加的产品副本进行迭代,它的 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"....}

正在改变当前项目。 Pre/post incremementing/decrementing 将改变它操作的当前对象引用。

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

但是您可以 return 增加值,当前值 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
        ),
  };

我怀疑您的代码按预期运行,因为您 do 正确地替换了整个购物车数组,并且您改变的项目无论如何都是您想要更新的项目,但这是指示性的您的 reducer 可能不是纯函数,即前一个状态在所有方面仍应等于前一个状态 reducer 计算下一个状态后

我做了几次这样的东西,试试这个代码:

const addItemToCart = (cartItems, cartItemToAdd) => {
  const existingCartItem = cartItems.find(
    (cartItem) => cartItem.id === cartItemToAdd.id
  );

  if (existingCartItem) {
    return cartItems.map((cartItem) =>
      cartItem.id === cartItemToAdd.id
        ? { ...cartItem, quantity: cartItem.quantity + 1 }
        : cartItem
    );
  }

  return [...cartItems, { ...cartItemToAdd, quantity: 1 }];
};

您似乎在使用 our official Redux Toolkit package,默认情况下会警告意外状态突变。太好了,因为在这种情况下它显然捕获了突变。

但是,更好的是Redux Toolkit uses Immer inside to let you write "mutating" state updates in reducers!。这意味着您的减速器逻辑可以简化为:

const cartSlice = createSlice({
  name: 'cart',
  initialState,
  reducers: {
    addToCartSuccess(state, action) {
      const item = state.cart.find(item => item.sku === action.payload.product.sku);
      if (item) {
        item.qty++;
      } else {
        action.product.qty = 1;
        state.cart.unshift(action.payload.product);
      }
    }
  }
})