首页 > 解决方案 > 太多的重新渲染/无限循环 - 在映射函数中设置状态

问题描述

我试图通过我的购物车中的项目进行映射,并将项目的 id 与数据对象中返回的 id 进行比较,然后在浏览器上显示一些信息,例如每个项目的数量等。我还试图添加一个总数购物车项目显示元素,但是,当我添加购物车中每个项目的数量(例如,一个项目的数量为 3,另一个项目的数量为 1 等)并尝试在映射函数中设置状态时,我得到一个重新渲染错误. 我从在线阅读中了解到,这是因为当您设置状态时,组件会重新呈现,但是,我不确定如何在不从函数内部设置状态的情况下使用购物车中的商品总数设置状态。

我还尝试在映射函数之外声明变量并在每次迭代时添加到该变量,但这也不起作用。

如果我在映射函数中控制台记录 cartItemsTotal,我会得到正确的值,即添加所有正在映射的项目的数量。

如果我在映射函数之外进行控制台记录,它始终为 0。这是因为范围吗?您不能在函数范围之外操作变量吗?

任何帮助表示赞赏。

谢谢

const CartIconSummary = ({data}) => {
  const [cartQuantity, setCartQuantity] = useState()
  const deleteCart = useCartDelete()
  const cart = useCart()
  
  let cartTotal = 0
  let vat = cartTotal * .23.toFixed(2)
  let cartItemsTotal = 0

  const displayCartItems = () => {
    setCartQuantity(cartItemsTotal)
    return cart && cart.map((cartItem, index) => {
      return data && data.map((dataItem) => {
          if(cartItem.id === dataItem.id) {
            cartTotal = cartTotal + dataItem.price * cartItem.quantity
            vat = vat + (dataItem.price * cartItem.quantity) * .23
            cartItemsTotal = cartItemsTotal + cartItem.quantity
            setCartQuantity(cartItemsTotal)
          return (
              <div key={index} className={`${className}CartItemContainer`}>
                  <div className={`${className}ImageContainer`}> 
                      <img className={`${className}Image`} src={data ? `${process.env.PUBLIC_URL}${dataItem.cartImage.slice(1)}` : ""} alt="cart-item-preview"/>
                  </div>
                  
                  <div className={`${className}CartItemNamePriceContainer`}> 
                      <div className={`${className}CartItemName`}> 
                          {dataItem.shortName}
                      </div>
                      <div className={`${className}CartItemPrice`}>
                          ${dataItem.price}
                      </div>
                  </div>
                  <div className={`${className}CartItemQuantity`}> 
                      x {cartItem.quantity}
                  </div>
              </div>
          )
          } else {
              return ""
          }
      })
    })
  }

  return (
    <>
    <div className={`${className}CartDeleteContainer`}> 
        <div className={`${className}CartQuantity`}> CART({cartQuantity ? cartQuantity : 0}) </div>
        <div className={`${className}CartDelete`} onClick={() => deleteCart([])}> Remove all </div>
    </div>
    {displayCartItems()}
    </>
  )
}

标签: javascriptreactjs

解决方案


目前你setCartQuantity在函数内部调用displayCartItems,这意味着每当组件渲染时,函数displayCartItems也会再次运行。这意味着当函数displayCartItems执行时,它将改变状态cartQuantitysetCartQuantity如果状态改变,整个组件将重新渲染,这意味着displayCartItems将再次执行。

为了解决这个问题,您应该使用useEffect钩子并添加cartItemsTotal依赖数组,以便setCartQuantity仅在cartItemsTotal更改时执行。


推荐阅读