简体   繁体   中英

How do I lift state up in this scenario?

The main problem right now is sharing the quantity of each item to the cart. I've read that I have to lift the state up to App.js to achive that, but then I have no clue how to create individual quantity states for each item (Right now they are created when Item component is being rendered. I tried using.map() on items (in App.js), but it doesn't work and gives an error. Here's some code:

  1. App.js
import { useState } from "react";
import Header from "./Components/Header";
import Cart from "./Components/Cart";
import Shop from "./Components/Shop";
import img1 from "./Pictures/food1.jpg";
import img2 from "./Pictures/food2.jpg";
import img3 from "./Pictures/food3.jpg";

function App() {
  const [showCart, setShowCart] = useState(false);
  const [items, setItems] = useState([
    {
      id: 1,
      name: "Spaghetti",
      price: "300$",
      img: img1,
      alt: "Plate of Spaghetti",
    },
    {
      id: 2,
      name: "Pizza",
      price: "500$",
      img: img2,
      alt: "Pizza",
    },
    {
      id: 3,
      name: "Tiramisu",
      price: "150$",
      img: img3,
      alt: "Tiramisu",
    },
  ]);
  // let [quantity, setQuantity] = useState(0);
  return (
    <div className="container">
      <Header onShowCart={() => setShowCart(!showCart)} />
      {showCart && <Cart items={items} />}
      <Shop items={items} />
    </div>
  );
}

export default App;
  1. Shop.js
import Item from "./Item";

const Shop = ({ items}) => {
  return (
    <div className="shop">
      {items.map((item) => (
        <Item
          key={item.id}
          item={item}
        />
      ))}
    </div>
  );
};

export default Shop;

  1. Item.js (Here's the [quantity, setQuantity] = useState(0) which I have to lift up.)
import { useState } from "react";
import ItemInfo from "./ItemInfo";

const Item = ({ item }) => {
  let [quantity, setQuantity] = useState(0);
  const addToCart = () => {
    console.log("Add Value");
    setQuantity(quantity + 1);
    console.log(quantity);
  };
  const removeFromCart = () => {
    console.log("Lower Value");
    quantity > 0 && setQuantity(quantity - 1);
    console.log(quantity);
  };

  return (
    <div className="item">
      <img className="image" src={item.img} alt={item.alt} />
      <ItemInfo
        name={item.name}
        price={item.price}
        onAdd={addToCart}
        onLower={removeFromCart}
        quantity={quantity}
      />
    </div>
  );
};

export default Item;

You can reuse items for quantity state and then create another function call updateQuantity and then pass it down to the child component Shop

import { useState } from "react";
import Header from "./Components/Header";
import Cart from "./Components/Cart";
import Shop from "./Components/Shop";
import img1 from "./Pictures/food1.jpg";
import img2 from "./Pictures/food2.jpg";
import img3 from "./Pictures/food3.jpg";

function App() {
  const [showCart, setShowCart] = useState(false);
  const [items, setItems] = useState([
    {
      id: 1,
      name: "Spaghetti",
      price: "300$",
      img: img1,
      alt: "Plate of Spaghetti",
      quantity: 0, //quantity state
    },
    {
      id: 2,
      name: "Pizza",
      price: "500$",
      img: img2,
      alt: "Pizza",
      quantity: 0, //quantity state
    },
    {
      id: 3,
      name: "Tiramisu",
      price: "150$",
      img: img3,
      alt: "Tiramisu",
      quantity: 0, //quantity state
    },
  ]);
  const updateQuantity = (updatedItem) => {
     const updatedItems = items.map(item => updatedItem === item ? {...updatedItem} : item) //update quantity from `updatedItem`
     setItems(updatedItems)
  }
  return (
    <div className="container">
      <Header onShowCart={() => setShowCart(!showCart)} />
      {showCart && <Cart items={items} />}
      <Shop items={items} updateQuantity={updateQuantity}/>
    </div>
  );
}

export default App;

Note that if items are controlled by API calls, you don't need to add quantity: 0 directly on items

Passing updateQuantity down to Shop and

import Item from "./Item";

const Shop = ({ items, updateQuantity }) => {
  return (
    <div className="shop">
      {items.map((item) => (
        <Item
          key={item.id}
          item={item}
          updateQuantity={updateQuantity}
        />
      ))}
    </div>
  );
};

export default Shop;

The last piece is updating your Item component logic

import { useState } from "react";
import ItemInfo from "./ItemInfo";

const Item = ({ item, updateQuantity }) => {
  const addToCart = () => {
    const currentQuantity = item.quantity || 0 //if `item.quantity` is undefined, it will use 0 as default value
    item.quantity = currentQuantity + 1
    updateQuantity(item) //lift `item` state to `App`
  };
  const removeFromCart = () => {
    if(!item.quantity) { //0 or undefined
       return //do nothing
    }
    item.quantity = item.quantity - 1
    updateQuantity(item) //lift `item` state to `App`
  };

  return (
    <div className="item">
      <img className="image" src={item.img} alt={item.alt} />
      <ItemInfo
        name={item.name}
        price={item.price}
        onAdd={addToCart}
        onLower={removeFromCart}
        quantity={item.quantity || 0} //can access quantity directly from `item`
      />
    </div>
  );
};

export default Item;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM