最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can I add the item to cart page in react - Stack Overflow

programmeradmin4浏览0评论

I am trying to add the items to a cart page when a user clicks the add to cart button.

import React from "react";
import "bootstrap";
import { useParams } from "react-router-dom";

function ItemDetail(handleClick) {
  const params = useParams();
  let { productCode, vendor, value}  = params;
  let item = {productCode, vendor, value};

  console.log(item);

  return (
    <>
      <div>
        <p>product id: {productCode}</p>
        <p>price: {value}</p>
        <p>vendor: {vendor}</p>
        <button onClick={() => handleClick(item)}>Add to Cart</button>
      </div>
    </>
  );
}

export default ItemDetail;

This is the cart page. Where I am to, render the item details from Item Details Page.

import React, { useState, useEffect } from "react";

const Cart = ({ cart, setCart, handleChange }) => {
  const [price, setPrice] = useState(0);

  const handleRemove = (id) => {
    const arr = cart.filter((item) => item.id !== id);
    setCart(arr);
    handlePrice();
  };

  const handlePrice = () => {
    let ans = 0;
    cart.map((item) => (ans += item.amount * item.price));
    setPrice(ans);
  };

  useEffect(() => {
    handlePrice();
  });

  console.log(setCart);

  return (
    <article>
      {cart.map((item) => (
        <div className="cart_box" key={item.id}>
          <div>
            <button onClick={() => handleChange(item, 1)}>+</button>
            <button>{item.amount}</button>
            <button onClick={() => handleChange(item, -1)}>-</button>
          </div>
          <div>
            <span>{item.price}</span>
            <button onClick={() => handleRemove(item.id)}>Remove</button>
          </div>
        </div>
      ))}
      <div className="total">
        <span>Total Price of your Cart</span>
        <span>R - {price}</span>
      </div>
    </article>
  );
};

export default Cart;

This is my item description page. I have fetched the items using params, this is only way I found easier for me.

import React, { useState, useEffect } from "react";
import { Row, Col } from "react-bootstrap";
import StyledCard from "../ponents/Card";

const Discover = (props, params, handleClick) => {
  const token = "not-the-actual-token";
  const [result, setResult] = useState([]);

  useEffect(() => {
    fetch(
      ".0.0/api/product/",
      {
        method: "GET",
        headers: { Authorization: `Bearer ${token}` },
      }
    )
      .then((res) => res.json())
      .then((json) => setResult(json));
  }, []);

  const cardStyle = {
    listStyle: "none",
    margin: 5,
    paddingLeft: 0,
    minWidth: 240,
  };
  return (
    <>
      <div className="latestdeals container my-5">
        <h1>All Products</h1>
        <Row className="hotcards">
          <Col className="colcard">
            {(result?.result || []).map((item) => (
              <div key={item.productCode} style={cardStyle}>
                <a href={`/itemDetail/${item.productCode}/${item.value}/${item.vendor}`}>
                  {" "}
                  <StyledCard
                    key={item.productCode}
                    name={item.vendor}
                    title={item.description}
                    price={item.value}
                    handleClick={handleClick}
                    item={item}
                  />
                </a>
              </div>
            ))}
          </Col>
        </Row>
      </div>
    </>
  );
};

export default Discover;

This is my App page

import "./index.scss";
import React, { useState } from "react";
import {
  BrowserRouter as Router,
  Route,
  Routes,
  useParams,
} from "react-router-dom";
import AllCategories from "./pages/all-catergories";
import Home from "./pages/home";
import Entertainment from "./pages/entertainment";
// import Cart from "./pages/_cart";
import Login from "./pages/login";
import Netflix from "./pages/netflix";
import Orders from "./pages/orders";
import SignUp from "./pages/sign-up";
// import Data2 from "./Data2";
import Products from "./pages/products";
// import Shop from "./ponents/Shop";
// import ProductDetail from "./pages/ProductDetail";
import Discover from "./pages/discover";
import ItemDetail from "./pages/itemDetail";
import Cart from "./pages/cart";

function App() {
  const [show, setShow] = useState(true);
  const [cart, setCart] = useState([]);

  const handleClick = (item) => {
    if (cart.indexOf(item) !== -1) return;
    setCart([...cart, item]);
  };

  const handleChange = (item, d) => {
    const ind = cart.indexOf(item);
    const arr = cart;
    arr[ind].amount += d;

    if (arr[ind].amount === 0) arr[ind].amount = 1;
    setCart([...arr]);
  };

  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="all-categories" exact element={<AllCategories />} />
        {/* <Route path="cart" exact element={<Cart />} /> */}
        <Route path="entertainment" exact element={<Entertainment />} />
        <Route path="login" exact element={<Login />} />
        <Route path="discover" exact element={<Discover />} />
        <Route path="netflix" exact element={<Netflix />} />
        <Route path="orders" exact element={<Orders />} />
        <Route path="sign-up" exact element={<SignUp />} />
        <Route path="products" element={<Products />} />
        <Route path="/itemDetail/:productCode/:value/:vendor" element={<ItemDetail />} />
        <Route path="/itemDetail/" element={<ItemDetail handleClick={handleClick}  />} />
        <Route path="/Cart/" exact element={<Cart cart={cart} setCart={setCart} handleChange={handleChange}/>} />
      </Routes>
    </Router>
  );
}

export default App;

I am trying to add the items to a cart page when a user clicks the add to cart button.

import React from "react";
import "bootstrap";
import { useParams } from "react-router-dom";

function ItemDetail(handleClick) {
  const params = useParams();
  let { productCode, vendor, value}  = params;
  let item = {productCode, vendor, value};

  console.log(item);

  return (
    <>
      <div>
        <p>product id: {productCode}</p>
        <p>price: {value}</p>
        <p>vendor: {vendor}</p>
        <button onClick={() => handleClick(item)}>Add to Cart</button>
      </div>
    </>
  );
}

export default ItemDetail;

This is the cart page. Where I am to, render the item details from Item Details Page.

import React, { useState, useEffect } from "react";

const Cart = ({ cart, setCart, handleChange }) => {
  const [price, setPrice] = useState(0);

  const handleRemove = (id) => {
    const arr = cart.filter((item) => item.id !== id);
    setCart(arr);
    handlePrice();
  };

  const handlePrice = () => {
    let ans = 0;
    cart.map((item) => (ans += item.amount * item.price));
    setPrice(ans);
  };

  useEffect(() => {
    handlePrice();
  });

  console.log(setCart);

  return (
    <article>
      {cart.map((item) => (
        <div className="cart_box" key={item.id}>
          <div>
            <button onClick={() => handleChange(item, 1)}>+</button>
            <button>{item.amount}</button>
            <button onClick={() => handleChange(item, -1)}>-</button>
          </div>
          <div>
            <span>{item.price}</span>
            <button onClick={() => handleRemove(item.id)}>Remove</button>
          </div>
        </div>
      ))}
      <div className="total">
        <span>Total Price of your Cart</span>
        <span>R - {price}</span>
      </div>
    </article>
  );
};

export default Cart;

This is my item description page. I have fetched the items using params, this is only way I found easier for me.

import React, { useState, useEffect } from "react";
import { Row, Col } from "react-bootstrap";
import StyledCard from "../ponents/Card";

const Discover = (props, params, handleClick) => {
  const token = "not-the-actual-token";
  const [result, setResult] = useState([]);

  useEffect(() => {
    fetch(
      "https://api.flash-internal.flash-group./emerceManagement/1.0.0/api/product/",
      {
        method: "GET",
        headers: { Authorization: `Bearer ${token}` },
      }
    )
      .then((res) => res.json())
      .then((json) => setResult(json));
  }, []);

  const cardStyle = {
    listStyle: "none",
    margin: 5,
    paddingLeft: 0,
    minWidth: 240,
  };
  return (
    <>
      <div className="latestdeals container my-5">
        <h1>All Products</h1>
        <Row className="hotcards">
          <Col className="colcard">
            {(result?.result || []).map((item) => (
              <div key={item.productCode} style={cardStyle}>
                <a href={`/itemDetail/${item.productCode}/${item.value}/${item.vendor}`}>
                  {" "}
                  <StyledCard
                    key={item.productCode}
                    name={item.vendor}
                    title={item.description}
                    price={item.value}
                    handleClick={handleClick}
                    item={item}
                  />
                </a>
              </div>
            ))}
          </Col>
        </Row>
      </div>
    </>
  );
};

export default Discover;

This is my App page

import "./index.scss";
import React, { useState } from "react";
import {
  BrowserRouter as Router,
  Route,
  Routes,
  useParams,
} from "react-router-dom";
import AllCategories from "./pages/all-catergories";
import Home from "./pages/home";
import Entertainment from "./pages/entertainment";
// import Cart from "./pages/_cart";
import Login from "./pages/login";
import Netflix from "./pages/netflix";
import Orders from "./pages/orders";
import SignUp from "./pages/sign-up";
// import Data2 from "./Data2";
import Products from "./pages/products";
// import Shop from "./ponents/Shop";
// import ProductDetail from "./pages/ProductDetail";
import Discover from "./pages/discover";
import ItemDetail from "./pages/itemDetail";
import Cart from "./pages/cart";

function App() {
  const [show, setShow] = useState(true);
  const [cart, setCart] = useState([]);

  const handleClick = (item) => {
    if (cart.indexOf(item) !== -1) return;
    setCart([...cart, item]);
  };

  const handleChange = (item, d) => {
    const ind = cart.indexOf(item);
    const arr = cart;
    arr[ind].amount += d;

    if (arr[ind].amount === 0) arr[ind].amount = 1;
    setCart([...arr]);
  };

  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="all-categories" exact element={<AllCategories />} />
        {/* <Route path="cart" exact element={<Cart />} /> */}
        <Route path="entertainment" exact element={<Entertainment />} />
        <Route path="login" exact element={<Login />} />
        <Route path="discover" exact element={<Discover />} />
        <Route path="netflix" exact element={<Netflix />} />
        <Route path="orders" exact element={<Orders />} />
        <Route path="sign-up" exact element={<SignUp />} />
        <Route path="products" element={<Products />} />
        <Route path="/itemDetail/:productCode/:value/:vendor" element={<ItemDetail />} />
        <Route path="/itemDetail/" element={<ItemDetail handleClick={handleClick}  />} />
        <Route path="/Cart/" exact element={<Cart cart={cart} setCart={setCart} handleChange={handleChange}/>} />
      </Routes>
    </Router>
  );
}

export default App;
Share Improve this question edited Apr 19, 2022 at 16:00 Drew Reese 204k18 gold badges244 silver badges273 bronze badges asked Apr 19, 2022 at 10:42 Manasseh CodesManasseh Codes 1251 gold badge1 silver badge16 bronze badges 8
  • 1 What is currently not working in your code? Do you get an error? – Emil Karlsson Commented Apr 19, 2022 at 12:19
  • 1 When I click the button no information is passed to the cart page – Manasseh Codes Commented Apr 19, 2022 at 12:28
  • 1 function ItemDetail(handleClick) is incorrect. The first (and only) parameter of a React function ponent is an object that contains all parameters you sent to the ponent. Thus, you should change it to function ItemDetail(params), and then change the button's onclick to look like this: <button onClick={() => params.handleClick(item)}>. – Emil Karlsson Commented Apr 19, 2022 at 12:38
  • 1 I can not do that, because Params has already been declared. – Manasseh Codes Commented Apr 19, 2022 at 12:55
  • Then call it something else, for example func_params. The important thing is that you change the onclick: <button onClick={() => func_params.handleClick(item)}> – Emil Karlsson Commented Apr 19, 2022 at 12:57
 |  Show 3 more ments

1 Answer 1

Reset to default 5

Issues

You've issues declaring React ponents, several of them aren't using props correctly. function ItemDetail(handleClick) { ... } should be function ItemDetail({ handleClick }) { ... }, and const Discover = (props, params, handleClick) => { ... } should probably be something like const Discover = ({ params, handleClick, ...props }) => { ... }. React ponents receive a single props object argument.

handleChange in App is also mutating state.

Solution

App

Fix the state mutation and ensure props are passed correctly to routed ponents. Use an item GUID to search the cart instead of shallow reference equality when checking to add to the cart. When updating cart quantities it is necessary to shallow copy the cart array and cart items that are being updated. Use functional state updates whenever possible so it's ensured it's updating from the previous state and not any stale state value closed over in scope.

function App() {
  const [show, setShow] = useState(true);
  const [cart, setCart] = useState([]);

  const handleClick = (item) => {
    // Update cart item quantity if already in cart
    if (cart.some((cartItem) => cartItem.productCode === item.productCode)) {
      setCart((cart) =>
        cart.map((cartItem) =>
          cartItem.productCode === item.productCode
            ? {
                ...cartItem,
                amount: cartItem.amount + 1
              }
            : cartItem
        )
      );
      return;
    }

    // Add to cart
    setCart((cart) => [
      ...cart,
      { ...item, amount: 1 } // <-- initial amount 1
    ]);
  };

  const handleChange = (productCode, d) => {
    setCart((cart) =>
      cart.flatMap((cartItem) =>
        cartItem.productCode === productCode
          ? cartItem.amount + d < 1
            ? [] // <-- remove item if amount will be less than 1
            : [
                {
                  ...cartItem,
                  amount: cartItem.amount + d
                }
              ]
          : [cartItem]
      )
    );
  };

  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="all-categories" element={<AllCategories />} />
        <Route path="entertainment" element={<Entertainment />} />
        <Route path="login" element={<Login />} />
        <Route path="discover" element={<Discover />} />
        <Route path="netflix" element={<Netflix />} />
        <Route path="orders" element={<Orders />} />
        <Route path="sign-up" element={<SignUp />} />
        <Route path="products" element={<Products />} />
        <Route
          path="/itemDetail/:productCode/:value/:vendor"
          element={<ItemDetail handleClick={handleClick} />}
        />
        <Route
          path="/Cart/"
          element={(
            <Cart
              cart={cart}
              setCart={setCart}
              handleChange={handleChange}
            />
          )}
        />
      </Routes>
    </Router>
  );
}

ItemDetail

Access/destructure the handleClick prop correctly. Pass the item's productCode to the callback.

function ItemDetail({ handleClick }) {
  const { productCode, vendor, value} = useParams();
  const item = { productCode, vendor, value };

  return (
    <div>
      <p>product id: {productCode}</p>
      <p>price: {value}</p>
      <p>vendor: {vendor}</p>
      <button onClick={() => handleClick(item)}>Add to Cart</button>
    </div>
  );
}

Discover

Correctly access/destructure the handleClick callback. Use the Link ponent instead of the raw anchor (<a />) tag. The anchor tag will reload the app which very likely isn't what you want to happen. Based on the code I suspect you don't actually need this handleClick since the ItemDetail ponent is passed it and adds to the cart

import { Link } from 'react-router-dom';

const cardStyle = {
  listStyle: "none",
  margin: 5,
  paddingLeft: 0,
  minWidth: 240,
};

const Discover = () => {
  const token = "not-the-actual-token";
  const [result, setResult] = useState([]);

  useEffect(() => {
    fetch(
      "https://api.flash-internal.flash-group./emerceManagement/1.0.0/api/product/",
      {
        method: "GET",
        headers: { Authorization: `Bearer ${token}` },
      }
    )
      .then((res) => {
        if (!res.ok) {
          throw new Error('Network response was not OK');
        }
        return res.json();
      })
      .then((data) => setResult(data.result))
      .catch(error => {
        // handle any rejected Promises, errors, etc...
      });
  }, []);

  return (
    <div className="latestdeals container my-5">
      <h1>All Products</h1>
      <Row className="hotcards">
        <Col className="colcard">
          {result.map((item) => (
            <div key={item.productCode} style={cardStyle}>
              <Link to={`/itemDetail/${item.productCode}/${item.value}/${item.vendor}`}>
                <StyledCard
                  name={item.vendor}
                  title={item.description}
                  price={item.value}
                  item={item}
                />
              </Link>
            </div>
          ))}
        </Col>
      </Row>
    </div>
  );
};

Cart

Don't store the cart total in state, it is easily derived from the cart state.

const Cart = ({ cart, setCart, handleChange }) => {
  const handleRemove = (productCode) => {
    setCart(cart => cart.filter(item => item.productCode !== productCode));
  };

  const price = cart.reduce((total, item) => total + item.amount * item.price, 0);

  return (
    <article>
      {cart.map((item) => (
        <div className="cart_box" key={item.id}>
          <div>
            <button onClick={() => handleChange(item.productCode, 1)}>+</button>
            <button>{item.amount}</button>
            <button onClick={() => handleChange(item.productCode, -1)}>-</button>
          </div>
          <div>
            <span>{item.price}</span>
            <button onClick={() => handleRemove(item.productCode)}>Remove</button>
          </div>
        </div>
      ))}
      <div className="total">
        <span>Total Price of your Cart</span>
        <span>R - {price}</span>
      </div>
    </article>
  );
};

发布评论

评论列表(0)

  1. 暂无评论