购物车中的初始数量和价格 React.js

Initial Quantity and Price in Shopping Cart React.js

所以我正在构建一个 React Shopping cart.I 能够添加总数量和总价格功能,但无法显示 cart.The 产品中存在的产品的初始价格和数量使用 axios 从后端获取并使用 useState 存储它。

这是代码

const CartPage = (props) => {
  const [cartProducts, setCartProducts] = useState([]);
  const [totalQuantity,setTotalQuantity] = useState();
  const [totalPrice,setTotalPrice] = useState(0);
  const [loading,setLoading]= useState(false);

  const { enqueueSnackbar,closeSnackbar} = useSnackbar();

  const authCtx = useContext(AuthContext)
  const token = authCtx.token;
  const userId = authCtx.userId;



  useEffect(() => {
    setLoading(true)
    let queryParams = '?auth=' + token + '&orderBy="userId"&equalTo="' + userId + '"';
    axiosInstance.get('/Cart.json'+queryParams).then((response) => {
      //console.log(response.data);
      let fetchProductData = [];
      for (let key in response.data) {
        fetchProductData.push({
          ...response.data[key],
          productId: key,
        });
      }

      //console.log(fetchProductData);
      setCartProducts(fetchProductData);
      setLoading(false)
    });
  },[token,userId]);
     

这是总价和总数量功能,它们在递增和递减计数器处理程序中被调用

 const totalQuantityHandler=()=>{
      const totalQuantityCount=cartProducts.reduce((total,product)=>{
        return total+product.quantity;
      },0)
      //console.log(totalQuantityCount)
      setTotalQuantity(totalQuantityCount)
      //console.log(cartProducts)
    }
    
    const totalPriceHandler=()=>{
      const totalPriceCount=cartProducts.reduce((total,product)=>{
        return total+product.price*product.quantity;
      },0)
      //console.log(totalPriceCount);
      setTotalPrice(totalPriceCount);
    }

const incrementCounterHandler = (index) =>{
  const updatedCart = [...cartProducts]
  updatedCart[index].quantity++
  setCartProducts(updatedCart);
  totalQuantityHandler();
  totalPriceHandler();
  //console.log(cartProducts)
}

const decrementCounterHandler=(index)=>{
  const updatedCart = [...cartProducts]
  updatedCart[index].quantity--
  setCartProducts(updatedCart);
  totalQuantityHandler();
  totalPriceHandler();
}

所以这是显示总数量和总价格的 JSX 部分代码

 <React.Fragment>
    {cartProducts.map((product, index) => {
      //console.log(product)
      return (
        <CartCard
          key={product.id}
          Image={product.productImage}
          Title={product.productName}
          Price={product.price}
          Details={product.productDetails}
          removeFromCart={() => removeFromCartHandler("REMOVE",product.productId)}
          moveToFavorites={(event)=>moveToFavoritesHandler(event,product)}
          Quantity={product.quantity}
          incrementCounter={() => incrementCounterHandler(index)}
          decrementCounter={() => decrementCounterHandler(index)}
          onHandleCallBack={(value) => sizeChangeHandler(value,index)}
        />
      );
    })}
    <Divider style={{ height: "2px", backgroundColor: "#000" }} />
    <Box
      display="flex"
      alignItems="center"
      justifyContent="flex-end"
      padding="10px"
      margin="20px"
      marginBottom="0px"
    >
      <Typography variant="h6">
        SubTotal({totalQuantity} Items): Rs.{totalPrice}
      </Typography>
    </Box>
    <ButtonGroup cancelled={()=>cartPageCancelledHandler()} continued={()=>cartPageContinuedHandler()}/>
  </React.Fragment>

我尝试了很多方法,但似乎都不起作用。有没有更好的实现方式?

问题

这里的问题是 React 状态更新是异步处理的,因此当您将更新排队到 cartProducts 状态(即 setCartProducts(updatedCart);)时,它不会使用将要更新的状态改为使用当前渲染周期的状态。

I was able to add Total quantity and Total price functionalities but not able to display the initial price and quantity of products present in the cart. The products are fetched from backend using axios and storing it using useState.

您在获取数据后不调用实用函数,因此不会计算初始 totalQuantitytotalPrice 状态。

此外,当 incrementing/decrementing 数量时,您似乎也在改变购物车状态。

const incrementCounterHandler = (index) =>{
  const updatedCart = [...cartProducts]
  updatedCart[index].quantity++ // <-- mutation
  setCartProducts(updatedCart);
  totalQuantityHandler();
  totalPriceHandler();
  //console.log(cartProducts)
}

const decrementCounterHandler=(index)=>{
  const updatedCart = [...cartProducts]
  updatedCart[index].quantity-- // <-- mutation
  setCartProducts(updatedCart);
  totalQuantityHandler();
  totalPriceHandler();
}

解决方案

使用依赖于 cartProducts 数组的 useEffect 挂钩来计算 cartProducts 更新时的数量和价格状态,并从购物车更新程序函数中删除对实用程序函数的调用。这样,当 cartProducts 状态从其他安装效果初始化时,以及任何其他购物车状态更新时,将重新计算数量和价格。

useEffect(() => {
  totalQuantityHandler();
  totalPriceHandler();
}, [cartProduces]);

您必须浅复制正在更新的所有状态和嵌套状态。

const incrementCounterHandler = (index) => {
  setCartProducts(cart => cart.map((item, i) => i === index
    ? { ...item, quantity: item.quantity + 1 }
    : item
  );
};

const decrementCounterHandler = (index) => {
  setCartProducts(cart => cart.map((item, i) => i === index
    ? { ...item, quantity: item.quantity - 1 }
    : item
  );
};

事实上,因为这两个函数在本质上是相同的,所以我更喜欢并建议将它们结合起来并传入数量delta。我还建议使用柯里化函数来避免在附加回调时需要使用匿名函数。

const incrementCounterHandler = (index, value) => () => {
  setCartProducts(cart => cart.map((item, i) => i === index
    ? { ...item, quantity: item.quantity + value }
    : item
  );
};

用法:

<CartCard
  ...
  incrementCounter={incrementCounterHandler(index, 1)}
  decrementCounter={decrementCounterHandler(index, -1)}
  ...
/>

我还建议不要 将导出的数量和价格值存储在状态中。这些应该根据实际状态在每次渲染时计算。如果您担心在 CartPage 重新呈现但 cartProducts 状态没有重新呈现时重新计算,那么您可以记住这些值。

const { totalQuantity, totalPrice } = useMemo(() => {
  return cartProducts.reduce(({ totalQuantity, totalPrice }, { price, quantity }) => ({
      totalQuantity: totalQuantity + quantity,
      totalPrice: totalPrice + (quantity * price),
    }), {
      totalQuantity: 0,
      totalPrice: 0,
    });
}, [cartProducts]);