尽管使用扩展运算符进行状态复制,但 Redux 状态突变



为什么我在使用扩展运算符复制对象时收到状态突变警报? 我正在尝试使用 redux 制作购物车。当添加一个元素或减少其数量时,我调度一个更新 de 状态的操作。 在我的化简器中,如果尚未添加产品,我将返回带有新对象的状态数组的新副本。如果已经添加,我会使用 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"....}

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

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

我怀疑您的代码按预期运行,因为您确实正确替换了整个 cart 数组,并且您更改的项目无论如何都是您要更新的项目,但这表明您的化简器可能不是纯函数,即在化简器计算下一个状态,前一个状态在所有方面仍应等于前一个状态。

看起来您正在使用我们的官方 Redux 工具包包,默认情况下它会警告意外状态突变。 这很好,因为在这种情况下,它显然捕获了一个突变。

但是,更好的是,Redux Toolkit 在内部使用 Immer 来让你在化简器中编写"变异"状态更新! 这意味着您的化简器逻辑可以简化为:

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

我做了几次这样的事情,试试这段代码:

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

最新更新