我正在为电子商务网站实现购物车。购物车是由对象数组表示的状态变量 shopCart 。每个对象都包含有关产品的信息,例如标题和价格。我正在尝试实现一个“删除”按钮,该按钮实际上正在执行它所要执行的操作,即从 shopCart 状态中删除项目,但所做的更改未显示在屏幕渲染中。我可以清空购物车,但屏幕仍显示产品。这是购物车页面的主要代码:
return (
<div class={styles.container}>
<h1>Product</h1><h1>Quantity</h1><h1>Unit price</h1><h1>Total price</h1><div></div>
{
shopCart.map((product, i, array) => <CartItem key={product.id} product={product} index={i} array={array}/>)
}
</div>
)
这是CartItem.js的实现
const CartItem = (props) => {
let { shopCart, setShopCart } = useContext(Context);
let product = props.product;
// takes the identification of a shopping cart product and removes it from the cart
const decrease = (element) => {
shopCart.forEach((el, i) => {
if (el.hasOwnProperty('id')) {
if (el.id === element) {
let aux = shopCart;
aux.splice(i, 1);
setShopCart(aux);
}
}
})
}
return (
<div>
<img src={product.image}></img>
<h1>{product.quantity}</h1>
<h1>{product.price}</h1>
<h1>{product.price * product.quantity}</h1>
<button onClick={() => {
decrease(product.id);
}}>Remove</button>
</div>
)
}
为什么即使每次单击删除按钮都将购物车中的物品删除后,它仍不能正确呈现购物车?
答案 0 :(得分:4)
您正在变异状态。您保存对状态的引用,对其进行突变,然后将其保存回状态,因此数组引用永不变。当检查状态或道具是否更新时,React使用浅等式。
const decrease = (element) => {
shopCart.forEach((el, i) => {
if (el.hasOwnProperty('id')) {
if (el.id === element) {
let aux = shopCart; // <-- Saved state ref
aux.splice(i, 1); // <-- mutation
setShopCart(aux); // <-- Saved ref back to state
}
}
})
}
在react状态下更新数组的正确方法是将数组元素复制到新的数组引用中。通过按商品ID过滤当前购物车可以轻松完成此操作。我还建议更改参数名称,以便更清楚地表示其含义。
const decrease = (id) => {
setShopCart(shopCart => shopCart.filter(item => item.id !== id));
}
答案 1 :(得分:2)
您正在直接修改shopCart(辅助是参考),它既是上下文又是您要遍历的集合。您需要确保要更新购物车的副本并重置上下文。至少,您可以执行以下操作:
const decrease = (element) => {
shopCart.forEach((el, i) => {
if (el.hasOwnProperty('id')) {
if (el.id === element) {
let aux = shopCart.slice(); // makes a copy
aux.splice(i, 1);
setShopCart(aux);
}
}
})
}
但是,我建议使用Drew建议的方法。当前的方法并不理想。
答案 2 :(得分:1)
解决方案比您想象的简单得多。您可以使用array.filter按ID删除匹配的产品。
const CartItem = (props) => {
const { product} = props;
let { shopCart, setShopCart } = useContext(Context);
// takes the identification of a shopping cart product and removes it from the cart
const handleClick = (e) => {
const filteredShopCart = shopCart.filter(item => item.id !== product.id);
setShopCart(filteredShopCart);
};
return (
<div>
<img src={product.image}></img>
<h1>{product.quantity}</h1>
<h1>{product.price}</h1>
<h1>{product.price * product.quantity}</h1>
<button onClick={handleClick}>Remove</button>
</div>
);
};