获取所选项目及其计数

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.jscart.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>
    );
  }
}

问题

  1. 您有多个 AppProvider 组件,每个组件都为其包装的子组件提供不同的上下文。
  2. 初始 AppContext 形状与 实际 作为上下文值传递的形状不匹配。
  3. cartItems 状态未作为数组维护。
  4. 其他各种问题和模式

解决方案

  1. 删除所有无关的 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>
        );
      }
    }
    
  2. 修复上下文使其具有与提供的值相匹配的初始值。修复状态更新器以正确管理 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>
      );
    };
    
  3. 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>
      );
    };
    
  4. 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 它们成为一项更容易的任务。

演示