【问题标题】:React: setState doesn't re-render the componentReact:setState 不会重新渲染组件
【发布时间】:2020-10-09 07:10:13
【问题描述】:

我正在为电子商务网站实施购物车。购物车是一个由对象数组表示的状态变量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>
    )
}

为什么即使每次点击移除按钮后购物车项目都被移除,但它仍无法正确呈现购物车?

【问题讨论】:

标签: javascript reactjs


【解决方案1】:

问题

你正在改变状态。您保存对状态的引用,对其进行变异,然后将其保存回状态,因此数组引用永远不会改变。 React 在检查 state 或 props 是否更新时使用浅相等。

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

【讨论】:

    【解决方案2】:

    您正在直接修改 shopCart(aux 是一个参考),它既是上下文又是您正在迭代的集合。您需要确保您正在更新购物车的副本并重置上下文。至少,您可以执行以下操作:

        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 推荐的方法。目前的方法并不理想。

    【讨论】:

      【解决方案3】:

      解决方案比您想象的要简单得多。您可以使用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>
        );
      };
      

      【讨论】:

        猜你喜欢
        • 2021-01-17
        • 2020-02-13
        • 2020-04-18
        • 2018-09-01
        • 2019-10-05
        • 2023-03-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多