每当我单击添加到购物车按钮时,都会触发操作,但 redux 状态不会更新(初始状态没有改变,但操作被触发)。
const CartScreen = () => {
const { id } = useParams();
const { search } = useLocation();
const [searchParms] = useSearchParams();
const productId = id;
const qty = search ? Number(search.split("=")[1]) : 1;
const dispatch = useDispatch()
useEffect(() => {
if (productId){
dispatch(addToCart(productId, qty))
}
}, [dispatch, productId, qty])
return (
<div>
<h1>Add to CART</h1>
</div>
);
};
export default CartScreen
购物车操作
export const addToCart = (id, qty) => async (dispatch, getState) =>{
const {data} = await axios.get(`http://127.0.0.1:8000/api/products/${id}`)
dispatch({
type: CART_ADD_ITEM,
payload:{
product:data._id,
name:data.name,
image:data.image,
countInStock:data.countInStock,
qty
}
})
localStorage.setItem('cartItems', JSON.stringify(getState().cart.cartItems))
}
推车减速机
export const cartReducer = (state = { cartItems: []}, action) =>{
switch(action.type){
case CART_ADD_ITEM:
const item = action.payload
const existItem = state.cartItems.findIndex(x => x.product === item.product)
if (existItem){
return{
...state,
cartItems: state.cartItems.map(x =>
x.product === existItem.product ? item : x)
}
} else{
return{
...state,
cartItems:[...state.cartItems, item]
}
}
default:
return state
}
}
Redux 存储
const reducer = combineReducers({
productList: productListReducer,
productDetails: productDetailsReducer,
cart: cartReducer,
})
const initialState = {
cart:{cartItems:cartItemsFromStorage}
};
const middleware = [thunk];
const store = createStore(
reducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
从 redux 开发工具中,我可以看到我触发的操作。该项目正在进入购物车缩减器,因为当我控制台时.logitem
从 cartReducerconst item=action.payload
,我在浏览器控制台中获取特定项目,但 cartItem redux 状态仍为初始值,它没有更新
Array.prototype.find()- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
Array.prototype.findIndex()- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
使用 Array.prototype.findIndex() 基本上会查找并返回第一个找到的项目的索引,如果没有找到,则-1
。而 Array.prototype.find() 返回数组中与提供的条件匹配的第一个元素。
export const cartReducer = (state = { cartItems: [] }, action) => {
switch(action.type){
case CART_ADD_ITEM:
const item = action.payload;
// use Array.prototype.find() instead
// see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
const existItem = state.cartItems.find(x => x.product === item.product);
if (existItem){
return{
...state,
cartItems: state.cartItems.map(x =>
x.product === existItem.product ? item : x)
};
} else{
return{
...state,
cartItems: [...state.cartItems, item]
};
}
default:
return state;
}
};
问题是您正在搜索现有产品并返回找到的索引 (array.findIndex
),然后将索引值用作布尔条件 (if (existItem) {...}
)。
这不会像您期望的那样工作,因为所有非零数字都是真实的,而0
是假的。这意味着,如果没有购物车物料产品匹配该-1
,则返回该商品,逻辑会将其视为现有商品。稍后通过array.map
更新购物车时,情况会更加复杂...如果existItem
-1
这意味着没有匹配的产品,新state.cartItems
将是一个新数组,但它不包含新的item
对象。换句话说,它只是先前状态的副本。
cartItems
最初以空数组开始,因此existItem
首次将商品添加到购物车时将始终返回-1
。
当产品确实存在于cartItems
数组中并且它是第 0 个元素时,会发生额外的意外错误。existItem
将等于0
,因此是假的,item
将作为副本添加到数组cartItems
。
关于使用array.findIndex
和array.find
,@Chigbogu是正确的,尽管如果您只是检查购物车项目数组是否有该项目,我建议您使用array.some
。这表示您正在显式使用布尔值。将existItem
重命名为hasItem
或类似名称,以便名称也指示布尔值(这是按照惯例)。
export const cartReducer = (state = { cartItems: []}, action) =>{
switch(action.type) {
case CART_ADD_ITEM: {
const newItem = action.payload;
const hasItem = state.cartItems.some(item => item.product === newItem.product);
if (hasItem) {
return {
...state,
cartItems: state.cartItems.map(item =>
item.product === newItem.product ? newItem : item
)
}
} else {
return {
...state,
cartItems: [...state.cartItems, newItem]
}
}
}
default:
return state;
}
};