簡體   English   中英

React:setState 不會重新渲染組件

[英]React: setState doesn't re-render the component

我正在為電子商務網站實施購物車。 購物車是由對象數組表示的 state 變量shopCart 每個 object 都包含有關產品的信息,例如標題和價格。 我正在嘗試實現一個刪除按鈕,它實際上正在執行它的預期操作,即從shopCart state 中刪除項目,但屏幕渲染上沒有顯示更改。 我可以清空購物車,但屏幕仍然顯示產品。 下面是購物車頁面的主要代碼:

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

為什么它不能正確呈現購物車,即使在每次單擊刪除按鈕后購物車項目都被刪除?

問題

你正在改變 state。你保存對 state 的引用,改變它,然后將它保存回 state,所以數組引用永遠不會改變。 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 state 中更新 arrays 的正確方法是將數組元素復制到新的數組引用中。 這可以通過按項目 ID 過濾當前購物車輕松實現。 我還建議更改參數名稱,以便更清楚地表示它代表什么。

const decrease = (id) => {
  setShopCart(shopCart => shopCart.filter(item => item.id !== id));
}

您正在直接修改 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 推薦的方法。 當前的方法並不理想。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM