获取所选项目及其计数

IT技术 javascript reactjs next.js cart shopping-cart
2021-05-16 05:43:07

我正在尝试制作一个像这个网站一样的购物车应用程序,但使用reactjs

index.js : (将每个产品发送到 product component)

        {products.length > 0
          ? products.map((product) => (
              <Product key={product.id} product={product} />
            ))
          : ""}

组件/product.js

<div>
    {product?.price}
   <h3>
      {product.name ? product.name : ""}
   </h3>
   <div dangerouslySetInnerHTML={{ __html: product?.description }} />
</div>

我还有添加按钮 UI 开关代码,它看起来像,

在点击添加按钮之前,

------------
| ADD     +|
------------

点击添加按钮后,

-----------------
| -  {count}   +|
-----------------

目前一切正常,每个产品的相应计数单独添加到主页中。

同样在contextApi的帮助下制作AppContext并更新了购物车,例如,

  const addToCart = (product) => {
    if (+cart >= 0) {
      setCart(+cart + 1);
      setCartItems(product);
    }
  };

nav.js 中,我获得了产品的更新数量,但是当我点击包菜单(这是一个购物车页面)时,我无法获取上下文。

预期结果

在访问购物车页面时(点击标题中的购物袋菜单),页面将分别显示到目前为止选择的产品(带有名称和描述)及其数量。

当前结果:

无法获取 appcontext 数据并显示所选产品和数量。

工作片段:

使用 Tailwind 和 Next.js 进行编辑(分叉)

请帮助我实现在导航到购物车(袋子)页面时显示所选产品及其各自数量的结果..我为此苦苦挣扎了很久..所以我虚心地请求您帮助我解决正确的问题..大提前致谢..

2个回答

问题

  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阵列。useEffectcartItems数组状态更新时,使用钩子计算派生的总项目计数状态正确添加和更新项目/产品数量,并在数量达到 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删除所有本地项目计数状态时,可以从上下文中的状态访问数量。在项目计数上有条件地呈现“添加项目”和递增/递减按钮。

    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您的products数组中的所有项目/产品都添加了一个属性,以使匹配/识别它们变得更加容易。

演示

使用 Tailwind 和 Next.js 进行编辑(分叉)

您需要将您的 to 移动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>
    );
  }
}