如何在反应中将商品添加到购物车页面
How can I add the item to cart page in react
我正在尝试在用户单击“添加到购物车”按钮时将商品添加到购物车页面。
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;
这是购物车页面。我要去的地方,从项目详细信息页面呈现项目详细信息。
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;
这是我的物品描述页面。我已经使用参数获取了项目,这是我发现对我来说更容易的唯一方法。
import React, { useState, useEffect } from "react";
import { Row, Col } from "react-bootstrap";
import StyledCard from "../components/Card";
const Discover = (props, params, handleClick) => {
const token = "not-the-actual-token";
const [result, setResult] = useState([]);
useEffect(() => {
fetch(
"https://api.flash-internal.flash-group.com/ecommerceManagement/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;
这是我的应用页面
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 "./components/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;
问题
你在声明 React 组件时遇到了问题,其中有几个组件没有正确使用 props。 function ItemDetail(handleClick) { ... }
应该是 function ItemDetail({ handleClick }) { ... }
,而 const Discover = (props, params, handleClick) => { ... }
可能应该是 const Discover = ({ params, handleClick, ...props }) => { ... }
。 React 组件接收单个 props 对象参数。
handleChange
in App
也是变异状态。
解决方案
应用程序
修复状态突变并确保 props 正确传递给路由组件。在检查添加到购物车时,使用项目 GUID 来搜索购物车而不是浅引用相等性。更新购物车数量时,有必要浅复制正在更新的购物车数组和购物车项目。尽可能使用功能状态更新,以确保它是从以前的状态更新的,而不是范围内关闭的任何陈旧状态值。
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>
);
}
物品详情
Access/destructure handleClick
道具正确。将项目的 productCode
传递给回调。
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>
);
}
发现
正确地 access/destructure handleClick
回调。使用 Link
组件而不是原始锚点 (<a />
) 标签。锚标记将重新加载应用程序,这很可能不是您想要发生的事情。根据代码,我怀疑您实际上并不需要这个 handleClick
,因为 ItemDetail
组件已传递给它并添加到购物车
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.com/ecommerceManagement/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
状态中导出。
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>
);
};
我正在尝试在用户单击“添加到购物车”按钮时将商品添加到购物车页面。
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;
这是购物车页面。我要去的地方,从项目详细信息页面呈现项目详细信息。
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;
这是我的物品描述页面。我已经使用参数获取了项目,这是我发现对我来说更容易的唯一方法。
import React, { useState, useEffect } from "react";
import { Row, Col } from "react-bootstrap";
import StyledCard from "../components/Card";
const Discover = (props, params, handleClick) => {
const token = "not-the-actual-token";
const [result, setResult] = useState([]);
useEffect(() => {
fetch(
"https://api.flash-internal.flash-group.com/ecommerceManagement/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;
这是我的应用页面
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 "./components/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;
问题
你在声明 React 组件时遇到了问题,其中有几个组件没有正确使用 props。 function ItemDetail(handleClick) { ... }
应该是 function ItemDetail({ handleClick }) { ... }
,而 const Discover = (props, params, handleClick) => { ... }
可能应该是 const Discover = ({ params, handleClick, ...props }) => { ... }
。 React 组件接收单个 props 对象参数。
handleChange
in App
也是变异状态。
解决方案
应用程序
修复状态突变并确保 props 正确传递给路由组件。在检查添加到购物车时,使用项目 GUID 来搜索购物车而不是浅引用相等性。更新购物车数量时,有必要浅复制正在更新的购物车数组和购物车项目。尽可能使用功能状态更新,以确保它是从以前的状态更新的,而不是范围内关闭的任何陈旧状态值。
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>
);
}
物品详情
Access/destructure handleClick
道具正确。将项目的 productCode
传递给回调。
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>
);
}
发现
正确地 access/destructure handleClick
回调。使用 Link
组件而不是原始锚点 (<a />
) 标签。锚标记将重新加载应用程序,这很可能不是您想要发生的事情。根据代码,我怀疑您实际上并不需要这个 handleClick
,因为 ItemDetail
组件已传递给它并添加到购物车
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.com/ecommerceManagement/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
状态中导出。
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>
);
};