使用 Context API 在 React 中实现购物车功能 在 React JS 中实现购物车功能

2025-06-08

使用 Context API 实现 React 中的购物车功能

在 React JS 中实现购物车功能

在 React JS 中实现购物车功能

介绍

在本教程中,我们将使用 React JS 实现购物车功能。我们将使用 React Hooks 来管理购物车状态。我们将使用 Context API 将购物车状态传递给需要它的组件。我们将使用 Local Storage API 将购物车状态持久化到浏览器中。我们还将使用 Tailwind CSS 来设置应用程序的样式。

先决条件

要遵循本教程,您需要在机器上安装以下软件:

  • Node.js
  • npm

您还需要对 React JS 和 Tailwind CSS 有基本的了解。

入门

首先,我们将使用 vite 创建一个新的 React 应用程序。为此,请在终端中运行以下命令:



npm create vite@latest


Enter fullscreen mode Exit fullscreen mode

系统将提示您输入项目名称。输入项目名称,然后按 Enter 键。在本教程中,我们将项目命名为react-cart。系统还将提示您选择一个框架。选择React并按 Enter 键。系统还将提示您选择一个变体。选择Javascript并按 Enter 键。这将在名为 的文件夹中创建一个新的 React 应用程序react-cart。要启动该应用程序,请导航到该react-cart文件夹cd react-cart​​并在终端中运行以下命令:



npm run dev


Enter fullscreen mode Exit fullscreen mode

这将以开发模式启动应用程序。现在,您可以通过导航到 来在浏览器中打开该应用程序http://localhost:5173

安装 Tailwind CSS

要安装 Tailwind CSS,请在终端中运行以下命令:



npm install -D tailwindcss postcss autoprefixer


Enter fullscreen mode Exit fullscreen mode


npx tailwindcss init -p


Enter fullscreen mode Exit fullscreen mode

tailwind.config.js这将在项目根目录中创建一个文件。打开该tailwind.config.js文件并向其中添加以下代码:



/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/**/*.{js,jsx,ts,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}


Enter fullscreen mode Exit fullscreen mode

接下来,让我们清理文件夹index.css中的文件src。打开index.css文件并删除其中的所有代码。接下来,将以下代码添加到index.css文件中:



@tailwind base;
@tailwind components;
@tailwind utilities;


Enter fullscreen mode Exit fullscreen mode

我们还清理文件夹App.jsx中的文件src,使其看起来像这样:



function App() {
  return (
    <>
    </>
  )
}


Enter fullscreen mode Exit fullscreen mode

您也可以删除文件夹App.css中的文件src

创建产品组件

让我们创建一个名为 的新文件夹。在该文件夹中components创建一个名为 的新文件 我们将使用Dummy Json获取将在应用程序中显示的产品。为了获取产品,我们将使用钩子。我们还将使用钩子将产品存储在 状态中。让我们从包中导入和钩子。将以下代码添加到文件:srccomponentsProducts.jsx
useEffectuseStateuseEffectuseStatereactProducts.jsx



import { useEffect, useState } from "react";


Enter fullscreen mode Exit fullscreen mode

创建一个名为并导出的新函数Products。将以下代码添加到Products.jsx文件:



export default function Products() {
  return (
    <>
    </>
  )
}


Enter fullscreen mode Exit fullscreen mode

让我们初始化产品的状态。将以下代码添加到Products.jsx文件:



const [products, setProducts] = useState([]);


Enter fullscreen mode Exit fullscreen mode

接下来,让我们获取产品。我们将使用一个async函数来获取产品。将以下代码添加到Products.jsx文件:



async function getProducts() {
    const response = await fetch('https://dummyjson.com/products')  // fetch the products
    const data = await response.json() // convert the response to json
    setProducts(data.products) // set the products in the state to the products we fetched
  }


Enter fullscreen mode Exit fullscreen mode

接下来,我们来调用钩子getProducts中的函数useEffect。在文件中添加以下代码Products.jsx



useEffect(() => {
    getProducts()
  }, [])


Enter fullscreen mode Exit fullscreen mode

接下来,让我们在组件中显示产品Products。在组件的返回语句中Products,添加以下代码:



<div className='flex flex-col justify-center bg-gray-100'>
  <div className='flex justify-between items-center px-20 py-5'>
    <h1 className='text-2xl uppercase font-bold mt-10 text-center mb-10'>Shop</h1>
  </div>
  <div className='grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 px-10'>
    {
      products.map(product => (
        <div key={product.id} className='bg-white shadow-md rounded-lg px-10 py-10'>
          <img src={product.thumbnail} alt={product.title} className='rounded-md h-48' />
          <div className='mt-4'>
            <h1 className='text-lg uppercase font-bold'>{product.title}</h1>
            <p className='mt-2 text-gray-600 text-sm'>{product.description.slice(0, 40)}...</p>
            <p className='mt-2 text-gray-600'>${product.price}</p>
          </div>
          <div className='mt-6 flex justify-between items-center'>
            <button className='px-4 py-2 bg-gray-800 text-white text-xs font-bold uppercase rounded hover:bg-gray-700 focus:outline-none focus:bg-gray-700'>Add to cart</button>
          </div>
        </div>
      ))
    }
  </div>
</div>


Enter fullscreen mode Exit fullscreen mode

这将为每个产品显示一张卡片。每张卡片将显示产品图片、标题、描述和价格。每张卡片还会包含一个按钮,用于将产品添加到购物车。

导航到App.jsx并导入Products组件。将以下代码添加到App.jsx文件:



import Products from './components/Products'


Enter fullscreen mode Exit fullscreen mode

接下来我们在组件Products中显示该组件App,在组件的return语句中App,添加如下代码:



<Products />


Enter fullscreen mode Exit fullscreen mode

您的App.jsx文件现在应如下所示:



import Products from './components/Products'

function App() {
  return (
    <Products />
  )
}

export default App


Enter fullscreen mode Exit fullscreen mode

您的Products.jsx文件现在应如下所示:



import { useState, useEffect } from 'react'


export default function Products() {
  const [products, setProducts] = useState([])

  async function getProducts() {
    const response = await fetch('https://dummyjson.com/products')
    const data = await response.json()
    setProducts(data.products)
  }

  useEffect(() => {
    getProducts()
  }, [])

  return (
    <div className='flex flex-col justify-center bg-gray-100'>
      <div className='flex justify-between items-center px-20 py-5'>
        <h1 className='text-2xl uppercase font-bold mt-10 text-center mb-10'>Shop</h1>
        <h1 className='text-2xl uppercase font-bold mt-10 text-center mb-10'>Cart</h1>
      </div>
      <div className='grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 px-10'>
        {
          products.map(product => (
            <div key={product.id} className='bg-white shadow-md rounded-lg px-10 py-10'>
              <img src={product.thumbnail} alt={product.title} className='rounded-md h-48' />
              <div className='mt-4'>
                <h1 className='text-lg uppercase font-bold'>{product.title}</h1>
                <p className='mt-2 text-gray-600 text-sm'>{product.description.slice(0, 40)}...</p>
                <p className='mt-2 text-gray-600'>${product.price}</p>
              </div>
              <div className='mt-6 flex justify-between items-center'>
                <button className='px-4 py-2 bg-gray-800 text-white text-xs font-bold uppercase rounded hover:bg-gray-700 focus:outline-none focus:bg-gray-700'>Add to cart</button>
              </div>
            </div>
          ))
        }
      </div>
    </div>
  )
}


Enter fullscreen mode Exit fullscreen mode

在浏览器中打开该应用程序,您应该会看到显示的产品。

产品

创建购物车上下文

Context 是一种在组件树中传递数据的方式,无需在每一层手动向下传递 props。在本教程中,我们将使用 Context API 将购物车状态传递给需要它的组件。让我们创建一个名为 的新文件夹。在该文件夹中context创建一个名为 的新文件。我们将使用钩子来创建购物车上下文。我们还将使用钩子来存储购物车状态,并使用钩子在浏览器中持久化购物车状态。让我们从包中导入钩子。将以下代码添加到文件中:srccontextcart.jsxcreateContextuseStateuseEffectcreateContextuseStateuseEffectreactcart.jsx



import { createContext, useState, useEffect } from 'react'


Enter fullscreen mode Exit fullscreen mode

接下来,让我们创建购物车上下文。将以下代码添加到cart.jsx文件:



export const CartContext = createContext()


Enter fullscreen mode Exit fullscreen mode

接下来,让我们创建CartProvider组件。将以下代码添加到cart.jsx文件:



export const CartProvider = ({ children }) => {
}


Enter fullscreen mode Exit fullscreen mode

初始化购物车的状态。将以下代码添加到cart.jsx文件:



const [cartItems, setCartItems] = useState([])


Enter fullscreen mode Exit fullscreen mode

看看我们希望购物车如何工作,我们希望能够将商品添加到购物车、从购物车中移除商品以及清空购物车。让我们创建一个用于将商品添加到购物车的函数。将以下代码添加到文件cart.jsx



 const addToCart = (item) => {
  const isItemInCart = cartItems.find((cartItem) => cartItem.id === item.id); // check if the item is already in the cart

  if (isItemInCart) {
  setCartItems(
      cartItems.map((cartItem) => // if the item is already in the cart, increase the quantity of the item
      cartItem.id === item.id
          ? { ...cartItem, quantity: cartItem.quantity + 1 }
          : cartItem // otherwise, return the cart item
      )
  );
  } else {
  setCartItems([...cartItems, { ...item, quantity: 1 }]); // if the item is not in the cart, add the item to the cart
  }
};


Enter fullscreen mode Exit fullscreen mode

解释:

  • 我们使用该find方法来检查商品是否已在购物车中。该find方法返回数组中第一个满足所提供测试函数的元素的值。如果没有满足测试函数的值,undefined则返回 。
  • 如果商品已在购物车中,我们将使用此map方法增加购物车中商品的数量。该map方法会创建一个新数组,其中包含对调用数组中每个元素调用指定函数的结果。
  • 如果商品不在购物车中,我们将使用扩展运算符将该商品添加到购物车中。

让我们创建一个用于从购物车中移除商品的函数。将以下代码添加到cart.jsx文件:



 const removeFromCart = (item) => {
  const isItemInCart = cartItems.find((cartItem) => cartItem.id === item.id);

  if (isItemInCart.quantity === 1) {
    setCartItems(cartItems.filter((cartItem) => cartItem.id !== item.id)); // if the quantity of the item is 1, remove the item from the cart
  } else {
    setCartItems(
      cartItems.map((cartItem) =>
        cartItem.id === item.id
          ? { ...cartItem, quantity: cartItem.quantity - 1 } // if the quantity of the item is greater than 1, decrease the quantity of the item
          : cartItem
      )
    );
  }
};


Enter fullscreen mode Exit fullscreen mode

解释:

  • 我们使用该find方法来检查商品是否在购物车中。该find方法返回数组中第一个满足所提供测试函数的元素的值。如果没有满足测试函数的值,undefined则返回。
  • 如果商品数量为 1,我们将使用该filter方法从购物车中移除该商品。该filter方法会创建一个新数组,其中包含所有通过所提供函数测试的元素。
  • 如果商品数量大于 1,我们将使用此map方法减少购物车中商品的数量。该map方法会创建一个新数组,其中包含对调用数组中每个元素调用指定函数的结果。

让我们创建一个用于清空购物车的函数。将以下代码添加到cart.jsx文件:



const clearCart = () => {
  setCartItems([]); // set the cart items to an empty array
};


Enter fullscreen mode Exit fullscreen mode

解释:

  • 我们正在使用该setCartItems方法将购物车商品设置为空数组。

让我们创建一个函数来获取购物车总额。将以下代码添加到cart.jsx文件:



const getCartTotal = () => {
  return cartItems.reduce((total, item) => total + item.price * item.quantity, 0); // calculate the total price of the items in the cart
};


Enter fullscreen mode Exit fullscreen mode

上面代码的解释:

  • 我们使用该reduce方法来计算购物车中商品的总价。该reduce方法对数组的每个元素执行一个由您提供的 Reducer 函数,并最终生成一个输出值。

接下来,让我们使用useEffect钩子将购物车状态持久化到浏览器中。将以下代码添加到cart.jsx文件:



useEffect(() => {
  localStorage.setItem("cartItems", JSON.stringify(cartItems));
}, [cartItems]);


Enter fullscreen mode Exit fullscreen mode

解释:

  • 我们正在使用APIsetItem的方法localStorage在浏览器中设置购物车商品。该setItem方法设置指定商品的价值localStorage
  • 我们使用该JSON.stringify方法将购物车商品转换为字符串。该JSON.stringify方法将 JavaScript 对象或值转换为 JSON 字符串。
  • 对于实际应用程序,您将需要使用数据库来存储购物车商品,因为localStorageAPI 不安全并且容易被用户操纵。

我们还可以使用useEffect钩子从浏览器获取购物车商品。将以下代码添加到cart.jsx文件:



useEffect(() => {
    const cartItems = localStorage.getItem("cartItems");
    if (cartItems) {
    setCartItems(JSON.parse(cartItems));
    }
}, []);


Enter fullscreen mode Exit fullscreen mode

解释:

  • 我们正在使用APIgetItem的方法localStorage从浏览器获取购物车商品。该getItem方法返回指定商品的价值localStorage
  • 我们使用该JSON.parse方法将购物车商品转换为对象。该JSON.parse方法解析 JSON 字符串,并构造该字符串描述的 JavaScript 值或对象。

让我们将购物车商品的初始状态更新为从浏览器获取的购物车商品。将以下代码添加到cart.jsx文件:



const [cartItems, setCartItems] = useState(localStorage.getItem('cartItems') ? JSON.parse(localStorage.getItem('cartItems')) : [])


Enter fullscreen mode Exit fullscreen mode

这会将购物车商品的初始状态设置为我们从浏览器获取的购物车商品。如果浏览器中没有购物车商品,则购物车商品的初始状态将为空数组。

接下来,让我们将购物车状态传递给需要它的组件。将以下代码添加到cart.jsx文件:



return (
  <CartContext.Provider
    value={{
      cartItems,
      addToCart,
      removeFromCart,
      clearCart,
      getCartTotal,
    }}
  >
    {children}
  </CartContext.Provider>
);


Enter fullscreen mode Exit fullscreen mode

您的cart.jsx文件现在应如下所示:



import { createContext, useState, useEffect } from 'react'

export const CartContext = createContext()

export const CartProvider = ({ children }) => {
  const [cartItems, setCartItems] = useState(localStorage.getItem('cartItems') ? JSON.parse(localStorage.getItem('cartItems')) : [])

  const addToCart = (item) => {
    const isItemInCart = cartItems.find((cartItem) => cartItem.id === item.id);

    if (isItemInCart) {
      setCartItems(
        cartItems.map((cartItem) =>
          cartItem.id === item.id
            ? { ...cartItem, quantity: cartItem.quantity + 1 }
            : cartItem
        )
      );
    } else {
      setCartItems([...cartItems, { ...item, quantity: 1 }]);
    }
  };

  const removeFromCart = (item) => {
    const isItemInCart = cartItems.find((cartItem) => cartItem.id === item.id);

    if (isItemInCart.quantity === 1) {
      setCartItems(cartItems.filter((cartItem) => cartItem.id !== item.id));
    } else {
      setCartItems(
        cartItems.map((cartItem) =>
          cartItem.id === item.id
            ? { ...cartItem, quantity: cartItem.quantity - 1 }
            : cartItem
        )
      );
    }
  };

  const clearCart = () => {
    setCartItems([]);
  };

  const getCartTotal = () => {
    return cartItems.reduce((total, item) => total + item.price * item.quantity, 0);
  };

  useEffect(() => {
    localStorage.setItem("cartItems", JSON.stringify(cartItems));
  }, [cartItems]);

  useEffect(() => {
    const cartItems = localStorage.getItem("cartItems");
    if (cartItems) {
      setCartItems(JSON.parse(cartItems));
    }
  }, []);

  return (
    <CartContext.Provider
      value={{
        cartItems,
        addToCart,
        removeFromCart,
        clearCart,
        getCartTotal,
      }}
    >
      {children}
    </CartContext.Provider>
  );
};


Enter fullscreen mode Exit fullscreen mode

使用购物车上下文

现在我们已经创建了购物车上下文,让我们AppCartProvider组件包装它。打开文件夹main.jsx中的文件src并导入CartProvider组件。在文件中添加以下代码main.jsx



import { CartProvider } from './context/cart'


Enter fullscreen mode Exit fullscreen mode

接下来我们AppCartProvider组件包装一下组件,在文件中添加如下代码main.jsx



<CartProvider>
  <App />
</CartProvider>


Enter fullscreen mode Exit fullscreen mode

您的main.jsx文件现在应如下所示:



import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import { CartProvider } from './context/cart.jsx'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <CartProvider>
      <App />
    </CartProvider>
  </React.StrictMode>,
)


Enter fullscreen mode Exit fullscreen mode

接下来,让我们CartContext从文件夹cart中的文件导入context。将以下代码添加到Products.jsx文件:



import { CartContext } from '../context/cart'


Enter fullscreen mode Exit fullscreen mode

我们还需要useContextreact包中导入钩子。更新文件中的 import 语句Products.jsx,如下所示:



import { useContext, useEffect, useState } from 'react'


Enter fullscreen mode Exit fullscreen mode

接下来,让我们使用useContext钩子来获取购物车状态。将以下代码添加到Products.jsx文件:



const { cartItems, addToCart } = useContext(CartContext)


Enter fullscreen mode Exit fullscreen mode

接下来,让我们更新addToCart按钮,使其使用addToCart购物车上下文中的函数。更新addToCart按钮使其如下所示:



<button onClick={() => addToCart(product)} className='px-4 py-2 bg-gray-800 text-white text-xs font-bold uppercase rounded hover:bg-gray-700 focus:outline-none focus:bg-gray-700'>Add to cart</button>


Enter fullscreen mode Exit fullscreen mode

现在,点击按钮时应该会将产品添加到购物车,但如果没有购物车页面,很难直观地看到这一点。
让我们先创建一个组件。在文件夹Cart创建一个名为 的新文件。我们将使用钩子来获取购物车状态。让我们包中导入钩子。将以下代码添加到文件中:Cart.jsxcomponentsuseContextuseContextreactCart.jsx



import { useContext } from 'react'


Enter fullscreen mode Exit fullscreen mode

接下来,让我们CartContext从文件夹cart中的文件导入context。将以下代码添加到Cart.jsx文件:



import { CartContext } from '../context/cart'


Enter fullscreen mode Exit fullscreen mode

创建一个名为并导出的新函数Cart。将以下代码添加到Cart.jsx文件:



export default function Cart() {
  return (
    <>
    </>
  )
}


Enter fullscreen mode Exit fullscreen mode

让我们使用useContext钩子来获取购物车状态。将以下代码添加到Cart.jsx文件:



const { cartItems, addToCart, removeFromCart, clearCart, getCartTotal } = useContext(CartContext)


Enter fullscreen mode Exit fullscreen mode

接下来,让我们在组件中显示购物车商品Cart。在组件的返回语句中Cart,添加以下代码:



<div className="flex-col flex items-center bg-white gap-8 p-10 text-black text-sm">
  <h1 className="text-2xl font-bold">Cart</h1>
  <div className="flex flex-col gap-4">
    {cartItems.map((item) => (
      <div className="flex justify-between items-center" key={item.id}>
        <div className="flex gap-4">
          <img src={item.thumbnail} alt={item.title} className="rounded-md h-24" />
          <div className="flex flex-col">
            <h1 className="text-lg font-bold">{item.title}</h1>
            <p className="text-gray-600">{item.price}</p>
          </div>
        </div>
        <div className="flex gap-4">
          <button
            className="px-4 py-2 bg-gray-800 text-white text-xs font-bold uppercase rounded hover:bg-gray-700 focus:outline-none focus:bg-gray-700"
            onClick={() => {
              addToCart(item)
            }}
          >
            +
          </button>
          <p>{item.quantity}</p>
          <button
            className="px-4 py-2 bg-gray-800 text-white text-xs font-bold uppercase rounded hover:bg-gray-700 focus:outline-none focus:bg-gray-700"
            onClick={() => {
              removeFromCart(item)
            }}
          >
            -
          </button>
        </div>
      </div>
    ))}
  </div>
  {
    cartItems.length > 0 ? (
      <div className="flex flex-col justify-between items-center">
    <h1 className="text-lg font-bold">Total: ${getCartTotal()}</h1>
    <button
      className="px-4 py-2 bg-gray-800 text-white text-xs font-bold uppercase rounded hover:bg-gray-700 focus:outline-none focus:bg-gray-700"
      onClick={() => {
        clearCart()
      }}
    >
      Clear cart
    </button>
  </div>
    ) : (
      <h1 className="text-lg font-bold">Your cart is empty</h1>
    )
  }
</div>


Enter fullscreen mode Exit fullscreen mode

这将在购物车组件中显示购物车商品。每个购物车商品将显示商品图片、标题、价格和数量。每个购物车商品还会有一个按钮用于增加商品数量,还有一个按钮用于减少商品数量。购物车组件还会显示购物车中商品的总价,以及一个用于清空购物车的按钮。

现在,您可以使用 React 路由器选择从产品页面导航到购物车的最佳方式。在本教程中,我们将切换模态框来显示购物车。
Products组件中,让我们导入该Cart组件。将以下代码添加到Products.jsx文件:



import Cart from './Cart'


Enter fullscreen mode Exit fullscreen mode

我们来初始化模态框的状态。将以下代码添加到Products.jsx文件:



const [showModal, setShowModal] = useState(false)


Enter fullscreen mode Exit fullscreen mode

让我们创建一个切换模式的函数。将以下代码添加到Products.jsx文件:



const toggle = () => {
  setShowModal(!showModal)
}


Enter fullscreen mode Exit fullscreen mode

接下来,我们将添加一个按钮来切换模式。将以下代码添加到标签Products.jsx下方的文件h1



{!showModal && <button className='px-4 py-2 bg-gray-800 text-white text-xs font-bold uppercase rounded hover:bg-gray-700 focus:outline-none focus:bg-gray-700'
  onClick={toggle}
>Cart ({cartItems.length})</button>}


Enter fullscreen mode Exit fullscreen mode

这将显示一个按钮来切换模式。该按钮将显示购物车中的商品数量。

现在让我们Cart在点击按钮时显示模态框(组件)。在文件的Products.jsx最后一个结束div标签之前添加以下代码:



  <Cart showModal={showModal} toggle={toggle} />


Enter fullscreen mode Exit fullscreen mode

您的Products.jsx文件现在应如下所示:



import { useState, useEffect, useContext } from 'react'
import { CartContext } from '../context/cart.jsx'
import Cart from './Cart.jsx'


export default function Products() {
  const [showModal, setshowModal] = useState(false);
  const [products, setProducts] = useState([])
  const { cartItems, addToCart } = useContext(CartContext)

  const toggle = () => {
    setshowModal(!showModal);
  };

  async function getProducts() {
    const response = await fetch('https://dummyjson.com/products')
    const data = await response.json()
    setProducts(data.products)
  }

  useEffect(() => {
    getProducts()
  }, [])

  return (
    <div className='flex flex-col justify-center bg-gray-100'>
      <div className='flex justify-between items-center px-20 py-5'>
        <h1 className='text-2xl uppercase font-bold mt-10 text-center mb-10'>Shop</h1>
        {!showModal && <button className='px-4 py-2 bg-gray-800 text-white text-xs font-bold uppercase rounded hover:bg-gray-700 focus:outline-none focus:bg-gray-700'
          onClick={toggle}
        >Cart ({cartItems.length})</button>}
      </div>
      <div className='grid sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 px-10'>
        {
          products.map(product => (
            <div key={product.id} className='bg-white shadow-md rounded-lg px-10 py-10'>
              <img src={product.thumbnail} alt={product.title} className='rounded-md h-48' />
              <div className='mt-4'>
                <h1 className='text-lg uppercase font-bold'>{product.title}</h1>
                <p className='mt-2 text-gray-600 text-sm'>{product.description.slice(0, 40)}...</p>
                <p className='mt-2 text-gray-600'>${product.price}</p>
              </div>
              <div className='mt-6 flex justify-between items-center'>
                <button className='px-4 py-2 bg-gray-800 text-white text-xs font-bold uppercase rounded hover:bg-gray-700 focus:outline-none focus:bg-gray-700'
                  onClick={() => {
                    addToCart(product)
                  }
                  }
                >Add to cart</button>
              </div>
            </div>
          ))
        }
      </div>
      <Cart showModal={showModal} toggle={toggle} />
    </div>
  )
}


Enter fullscreen mode Exit fullscreen mode

让我们更新Cart组件以使用该showModalprop。打开Cart.jsx文件并更新Cart组件,使其如下所示:



import PropTypes from 'prop-types'
import { useContext } from 'react'
import { CartContext } from '../context/cart.jsx'

export default function Cart ({showModal, toggle}) {

  const { cartItems, addToCart, removeFromCart, clearCart, getCartTotal } = useContext(CartContext)


  return (
    showModal && (
      <div className="flex-col flex items-center fixed inset-0 left-1/4 bg-white dark:bg-black gap-8  p-10  text-black dark:text-white font-normal uppercase text-sm">
        <h1 className="text-2xl font-bold">Cart</h1>
        <div className="absolute right-16 top-10">
          <button
            className="px-4 py-2 bg-gray-800 text-white text-xs font-bold uppercase rounded hover:bg-gray-700 focus:outline-none focus:bg-gray-700"
            onClick={toggle}
          >
            Close
          </button>
        </div>
        <div className="flex flex-col gap-4">
          {cartItems.map((item) => (
            <div className="flex justify-between items-center" key={item.id}>
              <div className="flex gap-4">
                <img src={item.thumbnail} alt={item.title} className="rounded-md h-24" />
                <div className="flex flex-col">
                  <h1 className="text-lg font-bold">{item.title}</h1>
                  <p className="text-gray-600">{item.price}</p>
                </div>
              </div>
              <div className="flex gap-4">
                <button
                  className="px-4 py-2 bg-gray-800 text-white text-xs font-bold uppercase rounded hover:bg-gray-700 focus:outline-none focus:bg-gray-700"
                  onClick={() => {
                    addToCart(item)
                  }}
                >
                  +
                </button>
                <p>{item.quantity}</p>
                <button
                  className="px-4 py-2 bg-gray-800 text-white text-xs font-bold uppercase rounded hover:bg-gray-700 focus:outline-none focus:bg-gray-700"
                  onClick={() => {
                    removeFromCart(item)
                  }}
                >
                  -
                </button>
              </div>
            </div>
          ))}
        </div>
        {
          cartItems.length > 0 ? (
            <div className="flex flex-col justify-between items-center">
          <h1 className="text-lg font-bold">Total: ${getCartTotal()}</h1>
          <button
            className="px-4 py-2 bg-gray-800 text-white text-xs font-bold uppercase rounded hover:bg-gray-700 focus:outline-none focus:bg-gray-700"
            onClick={() => {
              clearCart()
            }}
          >
            Clear cart
          </button>
        </div>
          ) : (
            <h1 className="text-lg font-bold">Your cart is empty</h1>
          )
        }
      </div>
    )
  )
}

Cart.propTypes = {
  showModal: PropTypes.bool,
  toggle: PropTypes.func
}


Enter fullscreen mode Exit fullscreen mode

我们在购物车组件中添加了一个关闭按钮。该按钮将用于关闭购物车组件。此外,我在顶部添加了一些 Tailwind CSS 类,div以便从屏幕左侧插入购物车组件。

结论

我们的应用程序现已完成。您可以在浏览器中打开该应用程序并进行测试。

您还可以探索其他方法来改善应用程序的用户体验,我不会介绍这些方法,例如

  • Add to cart当产品已添加到购物车时,按钮可以变为数量选择器
  • 当用户向购物车添加/删除商品时向应用程序添加通知。您可以使用React Toastify库向应用程序添加通知。

我会在应用程序的源代码中实现这些功能。你可以在这里查看,也可以在这里
查看现场演示。

资源

感谢您阅读本教程。如有任何疑问,请随时通过电子邮件LinkedIn联系我

鏂囩珷鏉ユ簮锛�https://dev.to/anne46/cart-functionity-in-react-with-context-api-2k2f
PREV
为什么在 git 上创建分支是错误的
NEXT
您可能认为海盗最喜欢的编程语言是 R...