React在写一个购物车的redux toolkit时遇到了问题。核心代码如下:
import { createSlice } from "@reduxjs/toolkit";
const cartSlice = createSlice({
name: 'cart',
initialState: {
cartItems: [],
cartItemCount: 0
},
reducers: {
addProduct(state, action) {
const { imageUrl, name, price } = action.payload
let newCartItems = [...state.cartItems]
let flag = newCartItems.some((item, index, arr) => {
if(item.name == name) {
arr[index].quantity += 1
return true
}
})
if(!flag) {
newCartItems = [
...state.cartItems,
{ imageUrl, name, price, quantity: 1 }
]
}
const cartItemCount = newCartItems.reduce(
(prevTotal, currItem) => prevTotal + currItem.quantity, 0
)
return { cartItems: newCartItems, cartItemCount }
}
}
})
export const { addProduct, deleteProduct, incQuantity, decQuantity } = cartSlice.actions
export default cartSlice.reducer
核心逻辑是,调用addProduct来修改redux所管理的cartItems和cartItemCount,当向购物车中添加一个新的物品时,代码正常运行;但当反复添加一个物品时,代码报出如下错误:
搜下资料发现是因为redux使用immer,不允许在reducer中修改state值后还return,二者只能取其一。
因此,当添加一个新物品时,由于没有修改cartItems,因此可以有返回值,不报错。
但当添加一个重复的物品时,即使在最开始使用了let newCartItems = [...state.cartItems]
来创建一个新的对象,但由于state.cartItems
数组中保存的不是基本数据类型,而是一个对象,因此newCartItems
保存的是state.cartItems
中各个对象的引用,即
newCartItems == state.cartItems // false
newCartItems[0] == state.cartItems[0] // true
由此可得,添加一个新物品时,由于既修改了state,又return了新值,因此报出immer错误。
修改后的代码如下:
addProduct(state, action) {
const { imageUrl, name, price } = action.payload
let flag = state.cartItems.some((item, index, arr) => {
if(item.name == name) {
arr[index].quantity += 1
state.cartItemCount += 1
return true
}
})
if(!flag) {
state.cartItems.push({ imageUrl, name, price, quantity: 1 })
state.cartItemCount += 1
}
}
这里只是对state做了修改,而没有return新值,因此代码正常运行。