代码之家  ›  专栏  ›  技术社区  ›  The Noobest Guy

React状态显示奇怪行为

  •  -1
  • The Noobest Guy  · 技术社区  · 9 月前

    我是新来的反应和制作一个简单的购物车的咖啡店。每当我将商品添加到购物车时,如果该商品还没有在购物车中,那么我基本上会将其与其他商品一起添加并设置 quantity 财产 1. 每当我再次添加相同的项目时,我只需要取整个项目,并通过以下操作更新相应的项目数量 quantity++ 。但我不知道为什么数量会自动更新两个。我试过调试它,但我不明白为什么会发生这种情况,为什么它不是按1更新,而是按2更新。

    以下是我的应用程序组件:

    import CoffeeShop from "./CoffeeShop"
    
    function App() {
    
      return (
        <>
          <h1 style={{ textAlign: "center" }}>Coffee Shop</h1>
          <CoffeeShop />
        </>
      )
    }
    
    export default App

    这是我的CoffeeShop组件:

    在这个组件中,我正在处理添加到购物车的行为

    import "./CoffeeShop.css";
    import CoffeeItems from "./CoffeeItems";
    import ShoppingCart from "./ShoppingCart";
    import { useState } from "react";
    
    export default function CoffeeShop() {
    
        const [cartItems, setCartItems] = useState([]);
        const [totalPrice, setTotalPrice] = useState(0);
    
        const addToCart = (id, item) => {
            console.log(cartItems);
            setCartItems(currItems => {
                const idx = currItems.findIndex(cartItem => cartItem.id === id);
                if (idx !== -1) {
                    const newItems = [...currItems];
                    newItems[idx].quantity++;
                    return newItems;
                }
                return [...currItems, { ...item, quantity: 1 }];
            });
            setTotalPrice(currTotalPrice => currTotalPrice + item.price);
        };
    
    
    
        return (
            <div className="CoffeeShop">
                <CoffeeItems addToCart={addToCart} />
                <ShoppingCart cartItems={cartItems} totalPrice={totalPrice} />
            </div>
        );
    }

    这是我的CoffeeItems组件:

    import { useEffect } from "react";
    import { useState } from "react";
    import fetchProducts from "./productsApi";
    import CoffeeItem from "./CoffeeItem";
    import "./CoffeeItems.css";
    import { v4 as uid } from "uuid";
    
    export default function CoffeeItems({ addToCart }) {
    
        const [products, setProducts] = useState([]);
        const [isLoading, setIsLoading] = useState(true);
    
        useEffect(() => {
            const fetchData = async () => {
                setIsLoading(true);
                const data = await fetchProducts();
                setIsLoading(false);
                for (let product of data) {
                    product.id = uid();
                }
                setProducts(data);
            }
            fetchData();
    
        }, []);
    
    
        return (
            <div className="CoffeeItems">
    
                {isLoading && <h1>Loading...</h1>}
                {products.map(product => <CoffeeItem product={product} addToCart={addToCart} key={product.id} />)}
    
            </div>
        );
    }

    **CoffeeItems组件基本上获取模拟数据,每个产品如下:**

    {
            "id": 3,
            "name": "Tea set",
            "price": 39.99,
            "description": "This tea set is a complete tea-making solution for tea enthusiasts. It consists of a beautiful and functional kettle for boiling water and a set of delicate tea cups designed for serving tea. The kettle is made of ceramic and comes with a handle and spout for easy pouring. The tea cups are small and dainty with a simple yet elegant design. Whether for a quiet afternoon tea with a friend, a family gathering, or a special event, this tea set offers a classic and sophisticated way to enjoy a relaxing cup of tea.",
            "image": "alisher-sharip-mumpl9-D7Uc-unsplash.jpg"
        }
    

    这是我的CoffeeItem组件:

    import "./CoffeeItem.css";
    
    export default function CoffeeItem({ product, addToCart }) {
    
        const handleAddToCart = (e) => {
            e.preventDefault();
            addToCart(product.id, product);
        }
    
        return (
            <div className="CoffeeItem">
                <h2>{product.name}- ${product.price}</h2>
                <img src={product.image} alt="product image" />
                <div>
                    <button onClick={handleAddToCart}>Add to cart</button>
                </div>
            </div>
        );
    }

    这是我的购物车组件-:

    import "./ShoppingCart.css";
    import CartItem from "./CartItem";
    
    export default function ShoppingCart({ cartItems, totalPrice }) {
    
        return (
            <div className="ShoppingCart">
                <h1>Shopping Cart</h1>
                {cartItems.length === 0 && <h2>Your cart is empty</h2>}
                {cartItems.length > 0 && <h2>total: ${totalPrice}</h2>}
                {cartItems.map(cartItem => <CartItem cartItem={cartItem} key={cartItem.id} />)}
            </div>
        );
    }

    **这是我的CartItem组件:**

    import "./CartItem.css";
    
    export default function CartItem({ cartItem }) {
        return (
            <div className="CartItem">
                <h2>Name: {cartItem.name}</h2>
                <h3>Price: ${cartItem.price}</h3>
                <h3>Quantity: {cartItem.quantity}</h3>
            </div>
        );
    }

    在CoffeeShop组件中,当对购物车中已有的某个商品执行addCart处理程序时,它会在添加的代码中 +1 正确的但它实际上增加了 +2 根据相应产品的数量属性。我不知道为什么会这样。请帮忙。

    编辑

    我刚从main.jsx文件中删除,现在一切正常。但是为什么呢?

    这是main.jsx文件

    import { StrictMode } from 'react'
    import { createRoot } from 'react-dom/client'
    import App from './App.jsx'
    import './index.css'
    
    createRoot(document.getElementById('root')).render(
      <StrictMode>
        <App />
      </StrictMode>,
    )

    **当我移除时,一切正常。但是为什么呢**

    1 回复  |  直到 9 月前
        1
  •  1
  •   David    9 月前

    这很微妙,但你正在改变状态:

    newItems[idx].quantity++;
    

    这在React中总是要避免的,可能会导致像你看到的那样的错误。(具体来说,你所看到的也是 StrictMode rendering components twice .)

    从根本上说,在React中永远不要改变状态。制作阵列的浅拷贝是不够的:

    const newItems = [...currItems];
    

    因为两个数组仍然引用相同的对象。因此,在一个数组中编辑对象会在两个数组中都编辑它。你可以 项目 将数组转换为新数组,并在该投影中找到值时替换该值。例如,考虑一下:

    setCartItems(currItems => 
      const idx = currItems.findIndex(cartItem => cartItem.id === id);
      if (idx !== -1) {
        return currItems.map((item, i) => 
          i === idx ?
          { ...item, quantity: item.quantity + 1 } :
          item
        );
      }
      return [...currItems, { ...item, quantity: 1 }];
    });
    

    这里的想法是,作为 map 迭代 currItems 它专门寻找你的目标指数。对于该索引处的项,它返回一个全新的项,该项包含与现有项相同的属性,但具有新的 quantity 价值。对于数组的其他索引,它只返回现有项的原样。