获取所选项目及其计数
Get selected item and its count
我正在尝试制作类似 this site 的购物车应用程序,但使用的是 reactjs.
index.js:(将每个产品发送到产品component
)
{products.length > 0
? products.map((product) => (
<Product key={product.id} product={product} />
))
: ""}
components/product.js:
<div>
{product?.price}
<h3>
{product.name ? product.name : ""}
</h3>
<div dangerouslySetInnerHTML={{ __html: product?.description }} />
</div>
我还有 ADD 按钮 UI 开关代码,看起来像,
点击添加按钮之前,
------------
| ADD +|
------------
点击添加按钮后,
-----------------
| - {count} +|
-----------------
目前一切正常,每个产品的相应数量都会单独添加到主页中。
也在 contextApi 的帮助下制作了 AppContext
并更新了购物车,例如
const addToCart = (product) => {
if (+cart >= 0) {
setCart(+cart + 1);
setCartItems(product);
}
};
在 nav.js 中,我正在获取更新的产品数量,但是当我点击包菜单时(这是一个 购物车页面) ,我无法获取上下文。
预期结果
在访问购物车页面时(点击 header 中的购物袋菜单),该页面将分别显示到目前为止选择的产品(包括名称和描述)及其数量。
当前结果:
无法获取 appcontext 数据并显示所选产品及其数量。
工作代码段:
请帮助我实现在导航到购物车(包)页面时显示所选产品及其各自数量的结果。我为此苦苦挣扎了很长时间。所以我谦虚地请求你帮助我正确的解决方案..提前非常感谢..
您需要将 AppProvider
移动到 _app.js
并将其从 index.js
和 cart.js
中删除,然后两个页面将能够访问相同的上下文。
你的 _app.js
应该是这样的
import React from "react";
import App from "next/app";
import { AppProvider } from "../components/context/AppContext";
export default class TailwindApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<AppProvider>
<Component {...pageProps} />
</AppProvider>
);
}
}
问题
- 您有多个
AppProvider
组件,每个组件都为其包装的子组件提供不同的上下文。
- 初始
AppContext
形状与 实际 作为上下文值传递的形状不匹配。
cartItems
状态未作为数组维护。
- 其他各种问题和模式
解决方案
删除所有无关的 AppProvider
提供程序组件,仅使用一个将整个应用程序包装在 _app.js
.
中
import { AppProvider } from "../components/context/AppContext";
export default class TailwindApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<AppProvider>
<Component {...pageProps} />
</AppProvider>
);
}
}
修复上下文使其具有与提供的值相匹配的初始值。修复状态更新器以正确管理 cartItems
数组。当 cartItems
数组状态更新时,使用 useEffect
挂钩计算派生的项目总数状态。正确添加和更新 item/product 数量,并在数量达到 0 时删除项目。
import React, { useState, useEffect } from "react";
export const AppContext = React.createContext({
cart: 0,
cartItems: [],
setCart: () => {},
addToCart: () => {},
removeFromCart: () => {}
});
export const AppProvider = (props) => {
const [cart, setCart] = useState(0);
const [cartItems, setCartItems] = useState([]);
useEffect(() => {
setCart(cartItems.reduce((count, { quantity }) => count + quantity, 0));
}, [cartItems]);
const addToCart = (product) => {
setCartItems((items) => {
if (items.find(({ id }) => id === product.id)) {
return items.map((item) =>
item.id === product.id
? {
...item,
quantity: item.quantity + 1
}
: item
);
} else {
return [
...items,
{
...product,
quantity: 1
}
];
}
});
};
const removeFromCart = (product) => {
setCartItems((items) => {
const foundItem = items.find(({ id }) => id === product.id);
if (foundItem?.quantity > 1) {
return items.map((item) =>
item.id === product.id
? {
...item,
quantity: item.quantity - 1
}
: item
);
} else {
return items.filter(({ id }) => id !== product.id);
}
});
};
return (
<AppContext.Provider value={{ cart, addToCart, removeFromCart, cartItems }}>
{props.children}
</AppContext.Provider>
);
};
在Products.js
中删除所有本地项目计数状态,可以从上下文中的状态访问数量。有条件地在项目计数上呈现“添加项目”和 increment/decrement 按钮。
import Link from "next/link";
import { useContext } from "react";
import { AppContext } from "./context/AppContext";
const Product = (props) => {
const { product } = props;
const contextData = useContext(AppContext);
const count =
contextData.cartItems.find(({ id }) => id === product.id)?.quantity ?? 0;
const addToCart = (product) => () => {
contextData.addToCart(product);
};
const removeFromCart = (product) => () => {
contextData.removeFromCart(product);
};
return (
...
{count ? (
...
{count}
...
) : (
...
<span className="label">ADD</span>
...
)}
</div>
</div>
);
};
在 Cart.js
中,您可以导入和使用上下文以呈现和显示购物车项目。
import { useContext } from "react";
import { AppContext } from "../components/context/AppContext";
const Cart = () => {
const { cart, cartItems } = useContext(AppContext);
return (
<div>
<h1> Cart Page </h1>
<h2>Total Item Count: {cart}</h2>
<p>
<ul>
{cartItems.map(({ id, name, quantity }) => (
<li key={id}>
{name}: {quantity}
</li>
))}
</ul>
</p>
</div>
);
};
注意:请注意,id
属性 已添加到您的 [=25] 中的所有 items/products =] 数组使 matching/identifying 它们成为一项更容易的任务。
演示
我正在尝试制作类似 this site 的购物车应用程序,但使用的是 reactjs.
index.js:(将每个产品发送到产品component
)
{products.length > 0
? products.map((product) => (
<Product key={product.id} product={product} />
))
: ""}
components/product.js:
<div>
{product?.price}
<h3>
{product.name ? product.name : ""}
</h3>
<div dangerouslySetInnerHTML={{ __html: product?.description }} />
</div>
我还有 ADD 按钮 UI 开关代码,看起来像,
点击添加按钮之前,
------------
| ADD +|
------------
点击添加按钮后,
-----------------
| - {count} +|
-----------------
目前一切正常,每个产品的相应数量都会单独添加到主页中。
也在 contextApi 的帮助下制作了 AppContext
并更新了购物车,例如
const addToCart = (product) => {
if (+cart >= 0) {
setCart(+cart + 1);
setCartItems(product);
}
};
在 nav.js 中,我正在获取更新的产品数量,但是当我点击包菜单时(这是一个 购物车页面) ,我无法获取上下文。
预期结果
在访问购物车页面时(点击 header 中的购物袋菜单),该页面将分别显示到目前为止选择的产品(包括名称和描述)及其数量。
当前结果:
无法获取 appcontext 数据并显示所选产品及其数量。
工作代码段:
请帮助我实现在导航到购物车(包)页面时显示所选产品及其各自数量的结果。我为此苦苦挣扎了很长时间。所以我谦虚地请求你帮助我正确的解决方案..提前非常感谢..
您需要将 AppProvider
移动到 _app.js
并将其从 index.js
和 cart.js
中删除,然后两个页面将能够访问相同的上下文。
你的 _app.js
应该是这样的
import React from "react";
import App from "next/app";
import { AppProvider } from "../components/context/AppContext";
export default class TailwindApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<AppProvider>
<Component {...pageProps} />
</AppProvider>
);
}
}
问题
- 您有多个
AppProvider
组件,每个组件都为其包装的子组件提供不同的上下文。 - 初始
AppContext
形状与 实际 作为上下文值传递的形状不匹配。 cartItems
状态未作为数组维护。- 其他各种问题和模式
解决方案
删除所有无关的
中AppProvider
提供程序组件,仅使用一个将整个应用程序包装在_app.js
.import { AppProvider } from "../components/context/AppContext"; export default class TailwindApp extends App { render() { const { Component, pageProps } = this.props; return ( <AppProvider> <Component {...pageProps} /> </AppProvider> ); } }
修复上下文使其具有与提供的值相匹配的初始值。修复状态更新器以正确管理
cartItems
数组。当cartItems
数组状态更新时,使用useEffect
挂钩计算派生的项目总数状态。正确添加和更新 item/product 数量,并在数量达到 0 时删除项目。import React, { useState, useEffect } from "react"; export const AppContext = React.createContext({ cart: 0, cartItems: [], setCart: () => {}, addToCart: () => {}, removeFromCart: () => {} }); export const AppProvider = (props) => { const [cart, setCart] = useState(0); const [cartItems, setCartItems] = useState([]); useEffect(() => { setCart(cartItems.reduce((count, { quantity }) => count + quantity, 0)); }, [cartItems]); const addToCart = (product) => { setCartItems((items) => { if (items.find(({ id }) => id === product.id)) { return items.map((item) => item.id === product.id ? { ...item, quantity: item.quantity + 1 } : item ); } else { return [ ...items, { ...product, quantity: 1 } ]; } }); }; const removeFromCart = (product) => { setCartItems((items) => { const foundItem = items.find(({ id }) => id === product.id); if (foundItem?.quantity > 1) { return items.map((item) => item.id === product.id ? { ...item, quantity: item.quantity - 1 } : item ); } else { return items.filter(({ id }) => id !== product.id); } }); }; return ( <AppContext.Provider value={{ cart, addToCart, removeFromCart, cartItems }}> {props.children} </AppContext.Provider> ); };
在
Products.js
中删除所有本地项目计数状态,可以从上下文中的状态访问数量。有条件地在项目计数上呈现“添加项目”和 increment/decrement 按钮。import Link from "next/link"; import { useContext } from "react"; import { AppContext } from "./context/AppContext"; const Product = (props) => { const { product } = props; const contextData = useContext(AppContext); const count = contextData.cartItems.find(({ id }) => id === product.id)?.quantity ?? 0; const addToCart = (product) => () => { contextData.addToCart(product); }; const removeFromCart = (product) => () => { contextData.removeFromCart(product); }; return ( ... {count ? ( ... {count} ... ) : ( ... <span className="label">ADD</span> ... )} </div> </div> ); };
在
Cart.js
中,您可以导入和使用上下文以呈现和显示购物车项目。import { useContext } from "react"; import { AppContext } from "../components/context/AppContext"; const Cart = () => { const { cart, cartItems } = useContext(AppContext); return ( <div> <h1> Cart Page </h1> <h2>Total Item Count: {cart}</h2> <p> <ul> {cartItems.map(({ id, name, quantity }) => ( <li key={id}> {name}: {quantity} </li> ))} </ul> </p> </div> ); };
注意:请注意,id
属性 已添加到您的 [=25] 中的所有 items/products =] 数组使 matching/identifying 它们成为一项更容易的任务。