发布于 2026-01-06 4 阅读
0

从零开始构建全栈电子商务 React 应用:终极指南 API:开发页面 DEV 的全球展示挑战赛,由 Mux 呈现:展示你的项目!

从零开始构建全栈电子商务 React 应用:终极指南

API:

正在开发页面

由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!

介绍 :

用户友好、功能丰富的电子商务平台的需求日益增长,这种趋势已经蔓延开来,无论是亚马逊、沃尔玛还是 Shopify,都在转向自托管电子商务平台,以便在线销售和整理更好的商品,而无需让顾客前往实体店购买任何东西。

我的项目:

我非常热衷于技术,因为我相信技术可以解决一切问题,所以我开始学习技术,最终进入了 Web 开发领域。我选择 React JS 来构建一些东西,以练习我的技能,同时深入了解 React JS 的核心概念及其整个生态系统。

我希望构建一些现实世界的应用,以便招聘人员和其他人能够轻松地理解它们,因此我开发了 Agri Store,这是一个利用 React JS 功能的基本电子商务平台。

项目目标:

我的目标是通过编写大量代码来深入挖掘,我打算展示 React JS、React Router v6、Context API、MockBee、TailwindCSS、React Hot Toast 的功能,并集成产品列表、排序/筛选、身份验证、购物车/愿望清单管理、支付处理和购买历史记录等功能。

项目结构及主要特点:

我希望遵循行业最佳实践,将项目分门别类地放到不同的文件夹中,文件夹结构如下:

SRC 文件夹:众所周知,React JS 有一个单独的源 (src) 文件夹,其中包含所有逻辑和 UI 部分,通过组合所有内容,我们将所有内容链接到主应用程序 JS 文件,该文件提供 index.html 文件,它也是主源文件。

组件文件夹:组件是整个页面的一小部分 UI,如果某个组件被多次使用,我们不会重复创建相同的组件,而是创建一次,然后在任何页面的任何位置调用它。

上下文文件夹:上下文文件夹负责管理整个应用程序中的状态,它有助于将代码单独清理,并创建与我们正在构建的功能相关的文件和文件夹。

Pages 文件夹:页面与 React JS 中的其他网页并无不同,只是我们不是一次性构建整个页面,而是将页面分解成更小的组件。

服务文件夹:服务文件夹包含所有后端数据,这些数据可以托管为 JSON 文件,也可以从 API 中检索。

UTILS 文件夹:Utils 或 utility 文件夹通常包含主要库或受支持库的代码,这些代码都放在一个文件中,使你的代码更加简洁易读易懂。

页面结构解码:

我的项目包含多个页面,因为我还实现了动态路由,使用户能够在不同的页面中查看产品详情。

我已将以下页面添加到我的作品中。

  1. 用于展示我所提供的服务的着陆页或主页

  2. 产品列表页面将显示我拥有的产品数量及其价格,侧边栏部分则用于根据价格、评分和库存情况筛选产品。

  3. 每个产品的动态产品列表页面

  4. 在购物车页面,除了结账按钮外,您还可以增加或减少商品数量,也可以从购物车中移除商品。

  5. 订单和地址管理页面,可添加地址并进行付款。

  6. 订单确认页面,显示您的订单已成功收到。

  7. 愿望清单页面,用于添加产品以供日后参考。

  8. 个人资料管理页面,您可以在不同的标签页下查看您购买的订单、您添加的地址以及您的个人资料信息。

  9. 用户登录和注册的身份验证页面,以及模拟登录凭据。

图片描述

解读整个项目:

首先,我想介绍一下项目中普遍使用的通用组件,我还会附上代码片段和解释。

1. 应用顶部的标题




import { React, Link, useState } from "../../Utils/CustomUtils";

import {

useCartContext,

useFilterContext,

useWishlistContext,

} from "../../Context/AllContextIndex";

function Header() {

const [isMenuOpen, setIsMenuOpen] = useState(false);

const { cart } = useCartContext();

const { wish } = useWishlistContext();

const { dispatch } = useFilterContext();

const token = window.localStorage.getItem("token");

return (

<div>

<div class=" flex flex-row items-center justify-between w-full p-2 sm:px-4 shadow-xl shadow-xs bg-gray-700 fixed-top top">

<Link to="/">

<div class="ml-8 text-lg text-white hidden md:flex">Car-kit</div>

</Link>

<span class="w-full md:w-1/3 h-10 cursor-pointer border border-gray-300 text-sm rounded-full flex">

<input type="search" onChange={(e) => dispatch({ type: "SEARCHBAR", payload: e.target.value })} placeholder="Search"

class="flex-grow px-4 rounded-l-full rounded-r-full text-sm focus:outline-none"

/>

</span>

<div class="flex text-white text-2xl ">

<div class="flex w-48 justify-between ">

<Link to="/ProductListingPage">

<span class="material-icons "> store </span>

</Link>

<div class="">

<Link to="/WishlistPage">

<span class="material-icons "> favorite</span>

</Link>

<span class="w-4 h-4 rounded-full text-center absolute leading text-xs bg-red-500">

{wish.length}

</span>

</div>

<div class="navbadge">

<Link to="/CartPage">

<span class="material-icons"> shopping_cart </span>

</Link>

<span class="w-4 h-4 rounded-full text-center absolute leading text-xs bg-red-500">

{cart.length}

</span>

</div>

{!token ? (

<Link to="/LoginPage">

<span class="material-icons "> login </span>

</Link>

) : (

<Link to="/Accountpage">

<span class="material-icons "> account_circle </span>

</Link>

)}

</div>

</div>

</div>

</div>

);

}

export { Header }



Enter fullscreen mode Exit fullscreen mode

这段代码是一个名为 Header 的 React 组件,它很可能代表网站或 Web 应用程序的头部区域。让我们一步一步地分析这段代码:

导入:代码从其他文件导入必要的模块和函数。它从“../../Utils/CustomUtils”导入 React、Link 和 useState,并从“../../Context/AllContextIndex”导入自定义上下文钩子 useCartContext、useFilterContext 和 useWishlistContext。

函数组件头部:这是名为 Header 的主要 React 函数组件。

状态管理:它使用 useState hook 来管理 isMenuOpen 的状态,并将其初始化为 false。

上下文用法:它使用自定义上下文钩子(useCartContext、useFilterContext、useWishlistContext)从相应的上下文中获取状态值(购物车、愿望、调度)。

令牌检索:从本地存储中检索令牌。此令牌可用于身份验证。

JSX渲染:它返回JSX元素以渲染头部区域。头部包含各种元素,例如链接、搜索栏、图标等。

动态内容:它通过分别访问愿望清单数组和购物车数组的长度,动态显示愿望清单和购物车的长度。

条件渲染:根据令牌是否存在,有条件地渲染登录链接或帐户链接。

事件处理:它将 onChange 事件处理程序附加到搜索输入字段,当用户在搜索栏中输入内容时,该处理程序会分发类型为“SEARCHBAR”且输入值作为有效负载的操作。

CSS样式:内联CSS类用于设置元素样式。诸如flex、items-center、justify-between、w-full等类用于构建和设置头部区域的样式。

总的来说,这段代码表示一个头部组件,其中包含导航链接、搜索栏、愿望清单、购物车和登录/帐户图标,以及基于用户操作的动态内容。

2. 应用底部的页脚




import React from "../../Utils/CustomUtils";

import "../../Utils/CustomCSSUtils.css";

function Footer() {

return (

<div>

<footer class="text-gray-400 bg-gray-900 body-font fixed bottom-0 w-full">

<div class="container px-5 py-8 mx-auto flex items-center sm:flex-row flex-col ">

<a class="flex title-font font-medium items-center md:justify-start justify-center text-white">

<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-10 h-10 text-white p-2 bg-red-500 rounded-full" viewBox="0 0 24 24">

<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"></path>

</svg>

<span class="ml-3 text-xl">CarSale</span>

</a>

<p class="text-sm text-gray-400 sm:ml-4 sm:pl-4 sm:border-l-2 sm:border-gray-800 sm:py-2 sm:mt-0 mt-4">© 2023 CarSale —

<a href="https://prankurpandeyy.netlify.com" class="text-gray-500 ml-1" target="_blank" rel="noopener noreferrer">@prankurpandeyy</a>

</p>

<span class="inline-flex sm:ml-auto sm:mt-0 mt-4 justify-center sm:justify-start">

<a class="text-gray-400" href="https://fb.com/prankurpandeyy">

<svg fill="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-5 h-5" viewBox="0 0 24 24">

<path d="M18 2h-3a5 5 0 00-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 011-1h3z"></path>

</svg>

</a>

<a class="ml-3 text-gray-400" href="https://twitter.com/prankurpandeyy">

<svg fill="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-5 h-5" viewBox="0 0 24 24">

<path d="M23 3a10.9 10.9 0 01-3.14 1.53 4.48 4.48 0 00-7.86 3v1A10.66 10.66 0 013 4s-4 9 5 13a11.64 11.64 0 01-7 2c9 5 20 0 20-11.5a4.5 4.5 0 00-.08-.83A7.72 7.72 0 0023 3z"></path>

</svg>

</a>

<a class="ml-3 text-gray-400" href="https://instagram.com/prankurpandeyy">

<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-5 h-5" viewBox="0 0 24 24">

<rect width="20" height="20" x="2" y="2" rx="5" ry="5"></rect>

<path d="M16 11.37A4 4 0 1112.63 8 4 4 0 0116 11.37zm1.5-4.87h.01"></path>

</svg>

</a>

<a class="ml-3 text-gray-400" href="https://linkedin.com/in/prankurpandeyy">

<svg fill="currentColor" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="0" class="w-5 h-5" viewBox="0 0 24 24">

<path stroke="none" d="M16 8a6 6 0 016 6v7h-4v-7a2 2 0 00-2-2 2 2 0 00-2 2v7h-4v-7a6 6 0 016-6zM2 9h4v12H2z"></path>

<circle cx="4" cy="4" r="2" stroke="none"></circle>

</svg>

</a>

</span>

</div>

</footer>

</div>

);

}

export { Footer };



Enter fullscreen mode Exit fullscreen mode

这段代码定义了一个名为 `<footer>` 的 React 组件Footer,它很可能代表网站或 Web 应用程序的页脚部分。让我们来分析一下这段代码:

  1. 进口:
  • import React from "../../Utils/CustomUtils";React从 . 导入模块"../../Utils/CustomUtils"。此导入不会直接在组件中使用,但通常每个 React 组件文件都需要它。

  • import "../../Utils/CustomCSSUtils.css";"CustomCSSUtils.css"从目录中导入名为 `.css` 的 CSS 文件"../../Utils"。此 CSS 文件可能用于设置页脚组件中元素的样式。

  1. 功能组件页脚:
  • 这是名为 . 的主要 React 函数组件Footer

  • 它返回 JSX 元素以渲染页脚部分。

  1. JSX渲染:
  • 页脚由各种元素组成,例如徽标、文本、社交媒体个人资料链接等。

  • 该徽标是一个用锚点( )标签包裹的 SVG 图像<a>

  • 文本内容包括网站名称和版权信息。

  • 社交媒体链接由包裹在锚标签()中的 SVG 图标表示<a>

  1. CSS 类:
  • 内联 CSS 类用于设置元素样式。诸如text-gray-400` <footer>` bg-gray-900px-5`<footer>` py-8、`<footer>` 等类用于构建和设置页脚部分的样式。

  • CustomCSSUtils.css此外,还可以应用导入的 CSS 文件中的类( )来设置某些元素的样式。

  1. 出口:
  • export { Footer };这行代码导出Footer组件,使其可供其他文件导入。通过导出Footer组件,您可以使其在应用程序的其他部分中可用。

总的来说,这段代码表示一个页脚组件,其中包含品牌标识、文本内容以及指向社交媒体个人资料的链接,并使用 CSS 类进行样式设置。

3. 从产品列表页面到愿望清单和结账页面的产品卡片:




import { React, Link, useNavigate } from "../../Utils/CustomUtils";

import {

useWishlistContext,

useCartContext,

useProductContext,

} from "../../Context/AllContextIndex";

import { addToCart, removeFromCart } from "../../Services/CartServices";

import { addToWishlist, deleteWishList } from "../../Services/WishlistServices";

import "./ProductCard.css";

function ProductCard({ productCardData }) {

const { _id, image, title, price, rating, inStock } = productCardData;

const { wish } = useWishlistContext();

const { dispatch } = useProductContext();

const { cart } = useCartContext();

const navigate = useNavigate();

const token = localStorage.getItem("token");

return (

<div>

<div class="w-full h-full flex justify-center items-center">

<div class="relative p-4 flex justify-center rounded-xl cursor-pointer">

<div class="top-0 left-0 mt-3 px-2 rounded-lg absolute z-30 bg-green-500 text-gray-100 text-xs md:text-sm font-medium md:block">

{inStock === true ? `in Stock` : `out of stock`}

</div>

<div class="top-0 left-0 h-2 md:h-3 mt-5 px-2 absolute z-20 bg-green-500"></div>

<div class="top-0 left-0 h-2 md:h-3 mt-6 pl-5 rounded-3xl absolute z-0 bg-green-600"></div>

<div class="w-52 pb-2 bg-white rounded-xl z-10">

<div class="relative">

<img src={image} class="max-h-60 object-cover rounded-t-xl" alt=""/>

</div>

<div class="px-2 py-1">

<Link to={`/Productdetails/${_id}`}>

<div class="text-sm md:text-base font-bold pr-2">{title}</div>

</Link>

<div class="flex py-2">

<div class="bg-gray-200 p-1 mr-2 rounded-full text-xs font-medium text-gray-900"> ${price}k</div>

<div class="flex justify-between item-center">

<div class="flex items-center">

<svg xmlns="http://www.w3.org/2000/svg" class="h-3 md:h-5 md:w-5 text-yellow-500" viewBox="0 0 20 20" fill="currentColor">

<path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />

</svg>

<p class="text-gray-600 font-bold text-xs md:text-sm ml-1">

{rating}

<span class="text-gray-500 font-normal">

(76 rewiews)

</span>

</p>

</div>

</div>

</div>

<div className="flex flex-col justify-center items-center p-4">

{cart.some((prod) => prod._id === productCardData._id) ? (

<button class="p-1 flex mb-2 justify-center items-center bg-red-600 hover:bg-red-700 focus:ring-indigo-500 focus:ring-offset-indigo-200 text-white w-full transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 rounded-lg " onClick={(_id) =>

removeFromCart(productCardData._id, dispatch)}>CART-

<span class="material-icons">remove_shopping_cart </span>

</button>

) : (

<button class="p-1 flex mb-2 justify-center items-center bg-gray-700 hover:bg-indigo-700 focus:ring-indigo-500 focus:ring-offset-indigo-200 text-white w-full transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 rounded-lg "

onClick={() => addToCart(productCardData, dispatch)} >CART+

<span class="material-icons ">shopping_cart</span>

</button>

)}

{wish.some(

(wishlist) => wishlist._id === productCardData._id

) ? (

<button class="p-1 flex justify-center items-center bg-red-600 hover:bg-red-700 focus:ring-indigo-500 focus:ring-offset-indigo-200 text-white w-full transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 rounded-lg" onClick={(_id) => deleteWishList(productCardData._id, dispatch)}>WISHLIST- <span class="material-icons">favorite </span> </button>

) : (

<button

class="p-1 flex justify-center items-center bg-gray-700 hover:bg-indigo-700 focus:ring-indigo-500 focus:ring-offset-indigo-200 text-white w-full transition ease-in duration-200 text-center text-base font-semibold shadow-md focus:outline-none focus:ring-2 focus:ring-offset-2 rounded-lg " onClick={() => addToWishlist(productCardData, dispatch)}>

WISHLIST+

<span class="material-icons">favorite_border </span>

</button>

)}

</div>

</div>

</div>

</div>

</div>

</div>

);}

export default ProductCard;



Enter fullscreen mode Exit fullscreen mode

这段代码定义了一个名为 `<product_card>` 的 React 组件ProductCard,它通常用于在网站或 Web 应用程序中显示单个产品卡片。让我们来分析一下这段代码:

  1. 进口:
  • import { React, Link, useNavigate } from "../../Utils/CustomUtils";: Imports React, Link, 和useNavigatefrom "../../Utils/CustomUtils". 这些很可能是项目中使用的自定义实用函数或模块。

  • import { useWishlistContext, useCartContext, useProductContext } from "../../Context/AllContextIndex";:导入自定义上下文钩子useWishlistContext,,useCartContextuseProductContext来自"../../Context/AllContextIndex"

  • import { addToCart, removeFromCart } from "../../Services/CartServices";:导入函数addToCartremoveFromCart来自"../../Services/CartServices"。这些函数可能用于处理购物车中的商品添加和删除。

  • import { addToWishlist, deleteWishList } from "../../Services/WishlistServices";:导入函数addToWishlist这些函数可能用于向愿望清单添加项目和从愿望清单中删除项目。deleteWishList"../../Services/WishlistServices"

  • import "./ProductCard.css";导入一个名为 . 的 CSS 文件"ProductCard.css"

  1. 功能组件ProductCard
  • 这是名为 . 的主要 React 函数组件ProductCard

  • 它会接收道具,具体来说productCardData,其中可能包含有关要在卡片中显示的产品的信息。

  1. 解构道具:
  • 对prop 进行解构以提取相关数据productCardData例如_id,,,,,imagetitlepriceratinginStock
  1. 上下文用法:
  • 它使用自定义上下文钩子来访问购物车(cart)、愿望清单(wish)和产品(dispatch)上下文。
  1. 状态和导航:
  • 它使用useNavigate钩子来获取用于程序化导航的导航函数(navigate)。

  • 它从本地存储中检索令牌。

  1. JSX渲染:
  • 它返回 JSX 元素以渲染产品卡片。

  • 卡片包含产品详情,例如图片、标题、价格和评分。

  • 它会显示产品是否有库存。

  • 它根据购物车和愿望清单的状态,提供添加/移除商品的按钮。

  • 每个按钮都会通过提供的服务功能触发特定的操作(例如,添加到购物车、从愿望清单中移除)。

  1. CSS样式:
  • 它应用文件中定义的 CSS 类和样式"ProductCard.css"来设置产品卡片元素的样式。
  1. 出口:
  • export default ProductCard;这行代码将ProductCard组件导出为默认导出项,使其可供其他文件导入。通过将其导出为默认导出项,您ProductCard无需在其他文件中使用花括号即可导入和使用该组件。

总的来说,这段代码代表了一个可重用的组件(ProductCard),用于显示产品信息并提供在购物车和愿望清单中添加/移除产品的功能。它遵循最佳实践,包括分离关注点、使用自定义上下文和服务函数,以及应用 CSS 进行样式设置。

4. 身份验证页面以及地址管理器中的输入




import { React, Link, useNavigate, useEffect, useState } from "../../Utils/CustomUtils";

import "../../Utils/CustomCSSUtils.css";

import { useLoginContext } from "../../Context/AllContextIndex";

import { loginHandler } from "../../Services/AuthServices";

function LoginInputs() {

const { dispatch, email, password, name } = useLoginContext();

const navigate = useNavigate();

function submitLoginData() {

loginHandler(email, password, dispatch);

navigate("/ProductListingPage");

}

const [error, setError] = useState("");

const [isDisabled, setIsDisabled] = useState(true);

useEffect(() => {

if (email.length > 0 && password.length > 0) {

setError("");

setIsDisabled(false);

} else {

setError("All fields must be filled.");

setIsDisabled(true);

}

}, [email, password]);

function setGuestLoginData(e) {

e.preventDefault();

const email = "6prankur@gmail.com";

const password = "12345678";

const name = `Guest`;

dispatch({ type: "EMAIL", payload: email });

dispatch({ type: "PASSWORD", payload: password });

dispatch({ type: "NAME", payload: name });

}

return (

<div>

<section class="text-gray-400 bg-gray-900 body-font">

<div class="container px-5 py-24 mx-auto flex flex-wrap items-center">

<div class="lg:w-3/5 md:w-1/2 md:pr-16 lg:pr-0 pr-0">

<h1 class="title-font font-medium text-3xl text-white">Slow-carb next level shoindxgoitch ethical authentic, poko scenester</h1>

<p class="leading-relaxed mt-4">Poke slow-carb mixtape knausgaard, typewriter street art gentrify hammock starladder roathse. Craies vegan tousled etsy austin.</p>

</div>

<div class="lg:w-2/6 md:w-1/2 bg-gray-800 bg-opacity-50 rounded-lg p-8 flex flex-col md:ml-auto w-full mt-10 md:mt-0">

<h2 class="text-white text-lg font-medium title-font mb-5">Log In</h2>

<div>

<form onSubmit={submitLoginData}>

<div class="relative mb-4">

<label for="full-name" class="leading-7 text-sm text-gray-400">Email</label>

<input id="email" type="email" value={email} name="email"

onChange={(e) => dispatch({ type: "EMAIL", payload: e.target.value })}

class="w-full bg-gray-600 bg-opacity-20 focus:bg-transparent focus:ring-2 focus:ring-red-900 rounded border border-gray-600 focus:border-red-500 text-base outline-none text-gray-100 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"

placeholder="Enter your email"

/>

</div>

<div class="relative mb-4">

<label for="email" class="leading-7 text-sm text-gray-400">Password</label>

<input id="password" type="password" name="password" value={password} placeholder="enter your password" onChange={(e) => dispatch({ type: "PASSWORD", payload: e.target.value })}

class="w-full bg-gray-600 bg-opacity-20 focus:bg-transparent focus:ring-2 focus:ring-red-900 rounded border border-gray-600 focus:border-red-500 text-base outline-none text-gray-100 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"

/>

</div>

<div className="flex flex-col">

<input type='submit' class="text-white bg-red-500 border-0 py-2 px-8 focus:outline-none hover:bg-red-600 rounded text-lg cursor-pointer" />

<button class="text-white bg-blue-500 border-0 py-2 px-8 focus:outline-none hover:bg-blue-600 rounded text-lg mt-2" onClick={setGuestLoginData}>Guest Login</button>

</div>

</form>

</div>

<p class="text-xs mt-3">Literally you probably haven't heard of them jean shorts.

<Link to="/SignupPage" class="text-xs ml-2 text-blue-500 font-semibold">

<a href="#" class="font-medium text-blue-600 dark:text-blue-500 hover:underline">SignUp</a>

</Link>

</p>

</div>

</div>

</section>

</div>

);}

export default LoginInputs;



Enter fullscreen mode Exit fullscreen mode

这段代码定义了一个名为 `<component>` 的 React 组件LoginInputs,它很可能代表用户登录功能的表单。让我们来分析一下这段代码:

  1. 进口:
  • import { React, Link, useNavigate, useEffect, useState } from "../../Utils/CustomUtils";: Imports React, Link, useNavigate, useEffect, and useStatefrom "../../Utils/CustomUtils". 这些很可能是项目中使用的自定义实用函数或模块。

  • import "../../Utils/CustomCSSUtils.css";:导入一个名为 的 CSS 文件"CustomCSSUtils.css",大概是用于设置登录表单的样式。

  • import { useLoginContext } from "../../Context/AllContextIndex";useLoginContext:从以下位置导入自定义上下文钩子"../../Context/AllContextIndex"

  • import { loginHandler } from "../../Services/AuthServices";loginHandler:从导入一个函数"../../Services/AuthServices",该函数可能处理身份验证过程。

  1. 功能组件LoginInputs
  • 这是名为 . 的主要 React 函数组件LoginInputs

  • 它不直接接收任何道具。

  1. 上下文用法:
  • 它使用自定义上下文钩子useLoginContext来访问与登录相关的状态变量,例如emailpassworddispatch
  1. 状态管理:
  • 它初始化本地状态变量errorisDisabled使用useState钩子。

  • 这些状态用于管理错误消息,并根据表单验证结果禁用/启用提交按钮。

  1. 事件处理:
  • 它定义了提交登录数据和设置访客登录数据的事件处理程序。

  • submitLoginData()当登录表单提交时,会调用该函数。登录成功后,该loginHandler函数会跳转到产品列表页面。

  • setGuestLoginData()当点击“访客登录”按钮时,会调用此函数。它会在登录表单中设置预定义的访客登录数据。

  1. 效果钩子:
  • 它使用钩子在状态变量或变量发生变化useEffect时执行表单验证emailpassword

  • 如果两个字段都填写完整,则会清除所有现有错误并启用提交按钮。否则,会显示错误消息并禁用提交按钮。

  1. JSX渲染:
  • 它返回 JSX 元素以渲染登录表单。

  • 表单包含电子邮件和密码输入字段,以及提交按钮和“访客登录”按钮。

  • 它还包含一个注册页面的链接。

  1. CSS样式:
  • 它应用文件中定义的 CSS 类和样式"CustomCSSUtils.css"来设置登录表单元素的样式。
  1. 出口:
  • export default LoginInputs;:此行将组件导出LoginInputs为默认导出项,使其可供其他文件导入。

总的来说,这段代码代表了一个可重用的组件LoginInputs,用于显示登录表单、处理用户输入、执行表单验证以及与身份验证服务交互。它遵循最佳实践,包括分离关注点、使用自定义上下文和服务以及应用 CSS 进行样式设置。

API:

现在是时候构建页面并集成数据 API 了。在开始构建页面之前,现在是了解 API 及其集成部分以及我们如何在项目中使用它们的最佳时机。

什么是API:

API 代表应用程序编程接口,现在让我们逐一解释它们。

应用程序 - 在信息技术领域,应用程序是一种在线/离线工具,其目的是为了解决特定问题,其中包括业务逻辑,并负责在线记录和增长记录。这些记录通过前端记录到数据库中,而帮助实现这一点的机制称为后端。

编程——它是告诉计算机要执行哪些任务来解决问题的技术过程,在与计算机通信时,我们使用一些语言,这些语言就是编程语言,例如 C、C++ 和我最喜欢的 JavaScript。

接口 - 将接口视为后端数据和数据库之间的客户端,而无需暴露业务逻辑。

API理论部分已经讲解完毕,现在是时候展现真正的魔力了。

这是我通过 Mockbee API 调用获取的所有产品的示例代码。




import { React, toast, axios } from "../Utils/CustomUtils";



export async function getProdcutsData(dispatch) {

dispatch({ type: "LOADINGSPINNER", payload: true });

try {

await axios({

method: "GET",

url: `/api/products`,

}).then((response) =>

dispatch({ type: "APIPRODUCTDATA", payload: response.data.products })

);



dispatch({ type: "LOADINGSPINNER", payload: false });

} catch (erorr) {

toast.error(`Server is encountering some issues:`, erorr);

console.log(`Server is encountering some issues:`, erorr);

}

}



Enter fullscreen mode Exit fullscreen mode

这段代码是一个名为 `fetch` 的异步函数,getProdcutsData用于从 API 端点获取产品数据。让我们来分析一下这段代码:

  1. 导入:它从“../Utils/CustomUtils”模块导入必要的模块Reacttoast和。axios

  2. 函数定义:

  • async function getProdcutsData(dispatch)它定义了一个名为 `async` 的异步函数,getProdcutsData该函数接受一个dispatch函数作为参数。
  1. 调度操作:
  • dispatch({ type: "LOADINGSPINNER", payload: true })它会向“LOADINGSPINNER”类型的操作发送有效负载,true以指示应该显示加载指示器。
  1. API请求:
  • await axios({ method: "GET", url: "/api/products" })它使用 Axios 向“/api/products”端点发出 GET 请求,并等待响应。
  1. 处理响应:
  • .then((response) => dispatch({ type: "APIPRODUCTDATA", payload: response.data.products }))一旦收到响应,它就会products从响应中提取数据,并分发类型为“APIPRODUCTDATA”的操作,有效负载包含产品数据。
  1. 调度操作(装载完成):
  • dispatch({ type: "LOADINGSPINNER", payload: false })收到产品数据或遇到错误后,它会派发一个操作,通过将有效负载设置为来停止加载指示器false
  1. 错误处理:
  • catch (erorr)如果 API 请求过程中发生任何错误,它会捕获该错误。

  • toast.error(服务器遇到一些问题:, erorr)屏幕上会显示错误提示信息,表明服务器遇到了一些问题。

  • console.log(服务器遇到一些问题:, erorr)为了便于调试,它会将错误记录到控制台。

总而言之,这段代码从 API 端点获取产品数据,分发操作来管理加载状态,并使用 toast 通知和控制台日志记录适当地处理错误。

所有 API 的集成方式都类似,对于前端开发人员来说,精通 API 集成是您工作中至关重要且最重要的部分。

在集成之前,您需要检查并调用它。API 调用后,您会首先在控制台中收到响应,然后您需要调整响应以将其显示在屏幕上。正如我之前所说,这并不容易,而且非常关键。

在这个项目中,我使用了 20 多个 API 调用,每个调用都负责执行不同的任务。

正在开发页面

开发组件之后,下一个任务就是开发页面。在这里,事情会变得非常困难,因为你需要同时完成两件事:首先是集成 API 数据,其次是管理组件。

本项目共有八页,顺序如下:

  1. 首页

  2. 产品列表页面

  3. 单品浏览页面

  4. 购物车管理页面

  5. 愿望清单页面

  6. 结账页面

  7. 订单成功页面

  8. 个人资料管理页面

首页

首页是任何应用程序的主要页面,它描述了应用程序的功能。我的首页结构如下,以下是代码。




import React from "react";

import {

Footer,

Header,

Hero,

FeaturedBrands,

Spinner,

} from "../../Components/AllComponentIndex";

import { useProductDataContext } from "../../Context/ProductListingPageContext";

function Homepage() {

const { isLoading } = useProductDataContext();

return (

<div>

<Header />

{isLoading ? (

<Spinner />

) : (

<div className="mt-12">

<Hero />

<FeaturedBrands />

</div>

)}

<Footer />

</div>

);

}

export default Homepage;



Enter fullscreen mode Exit fullscreen mode

这段代码定义了一个名为 `<component>` 的 React 函数式组件Homepage。让我们来分析一下这段代码:

  1. 进口:
  • React导入 React 库以定义 React 组件。

  • Footer,,,,:从“../../Components/AllComponentIndex ”导入各种组件Header以便在组件中使用HeroFeaturedBrandsSpinnerHomepage

  • useProductDataContext:从“../../Context/ProductListingPageContext”导入useProductDataContext钩子以访问与产品列表页面相关的数据。

  1. 函数定义:
  • function Homepage() { ... }定义一个名为的功能组件Homepage
  1. 组件逻辑:
  • const { isLoading } = useProductDataContext();isLoading从钩子函数中解构状态useProductDataContext。此状态指示数据是否正在加载。
  1. 组件 JSX:
  • <div>打开组件的容器 div。

  • <Header />:渲染Header组件。

  • {isLoading ? (<Spinner />) : ( <div className="mt-12"> <Hero /> <FeaturedBrands /> </div> )}

  • 检查是否isLoading为真。

  • 如果isLoading为真,则渲染Spinner组件以指示数据正在加载。

  • 如果isLoading为 false,Hero则渲染FeaturedBrands包裹在带有className="mt-12".

  • <Footer />:渲染Footer组件。

  • </div>关闭组件的容器 div。

  1. 出口:
  • export default Homepage;:将该Homepage组件导出为默认导出项。

总而言之,该Homepage组件会渲染一个头部,在数据加载时显示一个加载指示器,并在数据加载完成后渲染一个包含特色品牌的展示区域。它利用上下文来管理加载状态以及来自指定索引文件的组件。

最终输出效果如下:

图片描述

产品列表页面

产品列表页面负责以网格视图列出所有产品,侧边栏包含各种筛选器,方便用户根据库存、价格和订单情况查找产品。以下是代码。




import { React, toast, useNavigate } from "../../Utils/CustomUtils";

import {

useCatagoriesFilterContext,

useProductDataContext,

} from "../../Context/AllContextIndex";

import {

Footer,

Header,

Spinner,

ProductCard,

Sidebar,

} from "../../Components/AllComponentIndex";

import "./ProductlistingPage.css";

function ProductlistingPage() {

const { isLoading } = useProductDataContext();

const { searchbarData } = useCatagoriesFilterContext();

return (

<div className="bg-gray-700 h-screen">

<Header />

<div className="flex justify-start items-start">

<Sidebar />

<div className="flex flex-wrap ml-64 mt-24 mb-8 items-center justify-center">

{isLoading ? (

<Spinner />

) : (

searchbarData.map((productCardData) => {

return (

<ProductCard

productCardData={productCardData}

key={productCardData._id}

/>

);

})

)}

</div>

</div>
</div>

);

}

export default ProductlistingPage;



Enter fullscreen mode Exit fullscreen mode

这段代码定义了一个名为 `<component>` 的 React 函数式组件ProductlistingPage。让我们来分析一下这段代码:

  1. 进口:
  • React,,toast从“../../Utils/CustomUtils”useNavigate导入 React 库toast、和hook。useNavigate

  • useCatagoriesFilterContextuseProductDataContext:从“../../Context/AllContextIndex”导入上下文钩子。

  • Footer,,,,:从“../../Components/AllComponentIndex ”导入各种组件Header以便在组件中使用SpinnerProductCardSidebarProductlistingPage

  1. 函数定义:
  • function ProductlistingPage() { ... }定义一个名为的功能组件ProductlistingPage
  1. 组件逻辑:
  • const { isLoading } = useProductDataContext();isLoading从钩子函数中解构状态useProductDataContext。此状态指示数据是否正在加载。

  • const { searchbarData } = useCatagoriesFilterContext();searchbarData:从钩子函数中解构数据useCatagoriesFilterContext。此数据表示基于类别筛选后的产品。

  1. 组件 JSX:
  • <div className="bg-gray-700 h-screen">打开一个带有灰色背景的容器div,该容器div覆盖屏幕的整个高度。

  • <Header />:渲染Header组件。

  • <div className="flex justify-start items-start">:打开一个带有弹性布局的 div,从左侧开始水平排列项目。

  • <Sidebar />:渲染Sidebar组件。

  • <div className="flex flex-wrap ml-64 mt-24 mb-8 items-center justify-center">:打开一个采用弹性布局的 div,包裹其内容,并应用边距和对齐样式。

  • {isLoading ? (<Spinner />) : ( searchbarData.map((productCardData) => { ... }))}Spinner:如果为真,则渲染组件isLoading。否则,遍历数组并为每个元素searchbarData渲染一个组件。ProductCard

  • </div>关闭采用弹性布局的 div 元素。

  • </div>关闭外部容器 div。

  1. 出口:
  • export default ProductlistingPage;:将该ProductlistingPage组件导出为默认导出项。

总而言之,该ProductlistingPage组件渲染一个头部、一个侧边栏和一个产品卡片列表。产品卡片会根据从上下文中获取的数据动态渲染,并在数据加载时显示一个加载指示器。

最终输出结果如下:

图片描述

单品浏览页面

单品视图是动态路由的最佳示例,这得益于 React Router,它允许启用动态路由,从而为每个产品创建一个单独的页面及其详细信息。

以下是示例代码:




import React from "react";

import {Footer,Header,SingleProductCard} from "../../Components/AllComponentIndex";

function SingleProductPage() {

return (

<div>

<Header />

<SingleProductCard />

<Footer />

</div>

);

}

export default SingleProductPage;



Enter fullscreen mode Exit fullscreen mode

这段代码定义了一个名为 `<component>` 的 React 函数式组件SingleProductPage。让我们来分析一下这段代码:

  1. 进口:
  • React导入 React 库以定义和使用 React 组件。

  • Footer,,HeaderSingleProductCard从“../../Components/AllComponentIndex”导入组件,以便在组件中使用SingleProductPage

  1. 函数定义:
  • function SingleProductPage() { ... }定义一个名为的功能组件SingleProductPage
  1. 组件 JSX:
  • <div>打开一个容器div。

  • <Header />:渲染Header组件。

  • <SingleProductCard />:渲染SingleProductCard组件。

  • <Footer />:渲染Footer组件。

  • </div>关闭容器 div。

  1. 出口:
  • export default SingleProductPage;:将该SingleProductPage组件导出为默认导出项。

总而言之,该SingleProductPage组件渲染一个页眉、一张产品卡片和一个页脚。它用作展示单个产品详细信息的页面。

让我们深入了解一下它的内部构造。<SingleProductCard />




import {React,useEffect,useState,axios,toast,useParams} from "../../Utils/CustomUtils";

import {useWishlistContext,useCartContext,useProductContext} from "../../Context/AllContextIndex";

import { Rating } from "../../Components/AllComponentIndex";

import "./SingleProductCard.css";

import { addToCart, removeFromCart } from "../../Services/CartServices";

import { addToWishlist, deleteWishList } from "../../Services/WishlistServices";

function SingleProductCard() {

const { wish } = useWishlistContext();

const { dispatch } = useProductContext();

const { cart } = useCartContext();

const [singleProduct, setSingleProduct] = useState([]);

const {_id,inStock,manufacturedBy,image,title,rating,price,description,categoryName,} = singleProduct;

const productId = useParams();

 // function to get the product data from the product id

function getProductById(productId) {

axios.get(`/api/products/${productId}`).then((res) => {

setSingleProduct(res.data.product);

}).catch((err) => {console.log(" err", err);

});

}

useEffect(() => {

toast.success(" Fetching single card data.");

getProductById(productId.id);

}, [productId]);


return (

<div>

<section class="text-gray-600 body-font overflow-hidden">

<div class="container px-5 py-24 mx-auto">

<div class="lg:w-4/5 mx-auto flex flex-wrap">

<img alt="ecommerce" class="lg:w-1/2 w-full lg:h-auto h-64 object-cover object-center rounded"

src={image && image}

/>

<div class="lg:w-1/2 w-full lg:pl-10 lg:py-6 mt-6 lg:mt-0">

<h1 class="text-gray-900 text-3xl title-font font-medium mb-1">

{title && title}

</h1>

<div class="flex mb-4">

<span class="flex items-center">

<svg fill="currentColor" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-4 h-4 text-indigo-500" viewBox="0 0 24 24">

<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>

</svg>

<svg

fill="currentColor" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-4 h-4 text-indigo-500" viewBox="0 0 24 24" >

<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>

</svg>

<svg fill="currentColor" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-4 h-4 text-indigo-500" viewBox="0 0 24 24">

<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>

</svg>

<svg fill="currentColor" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-4 h-4 text-indigo-500" viewBox="0 0 24 24">

<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>

</svg>

<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-4 h-4 text-indigo-500" viewBox="0 0 24 24">

<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>

</svg>

<span class="text-gray-600 ml-3">4 Reviews</span>

</span>

</div>

<p class="leading-relaxed">{description && description}</p>

<div class="flex mt-6 items-center pb-5 border-b-2 border-gray-100 mb-5">

<div class="flex ml-6 items-center">

<div class="relative">

<span class="absolute right-0 top-0 h-full w-10 text-center text-gray-600 pointer-events-none flex items-center justify-center">

<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-4 h-4" viewBox="0 0 24 24">

<path d="M6 9l6 6 6-6"></path>

</svg>

</span>

</div>

</div>

</div>

<div class="flex">

<span class="title-font font-medium text-2xl text-gray-900">

${price && price}

</span>

{cart.some((prod) => prod._id === _id) ? (

<button class="flex ml-auto text-white bg-red-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded" onClick={(_id) => removeFromCart(_id, dispatch)}>

{" "}

REMOVE FROM CART

<span class="material-icons buttonmi">

remove_shopping_cart{" "}

</span>

</button>

) : (

<button

class="flex ml-auto text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded" onClick={() => addToCart(singleProduct, dispatch)}>

ADD TO CART <span class="material-icons buttonmi"> shopping_cart</span>

</button>

)}

{wish.some((wishlist) => wishlist._id === _id) ? (

<button

class="rounded-full w-10 h-10 bg-red-500 p-0 border-0 inline-flex items-center justify-center text-white ml-4"

onClick={(_id) => deleteWishList(_id, dispatch)}

>

<span class="material-icons buttonmi">

favorite_border{" "}

</span>

</button>

) : (

<button

onClick={() => addToWishlist(singleProduct, dispatch)}

class="rounded-full w-10 h-10 bg-gray-200 p-0 border-0 inline-flex items-center justify-center text-gray-500 ml-4"

>

<svg fill="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="w-5 h-5" viewBox="0 0 24 24" >

<path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z"></path>

</svg>

</button>

)}

</div>

</div>

</div>

</div>

</section>

</div>

);

}

export default SingleProductCard;



Enter fullscreen mode Exit fullscreen mode

以下是对代码的完整解释。

这段代码定义了一个名为 `<component>` 的 React 函数式组件SingleProductCard。让我们来分析一下这段代码:

  1. 进口:
  • React导入 React 库以定义和使用 React 组件。

  • useEffect,,,,:从“ ../../Utils/CustomUtils ”导入钩子和库useState用于管理组件状态、发出HTTP请求、显示通知和访问路由参数。axiostoastuseParams

  • useWishlistContext,,useCartContextuseProductContext从“../../Context/AllContextIndex”导入自定义钩子,以访问与愿望清单、购物车和产品相关的上下文数据。

  • RatingRating:从“../../Components/AllComponentIndex”导入组件。

  1. 函数定义:
  • function SingleProductCard() { ... }定义一个名为的功能组件SingleProductCard
  1. 组件状态:
  • const [singleProduct, setSingleProduct] = useState([]);使用钩子声明状态变量singleProduct及其设置函数useState。它singleProduct使用空数组进行初始化。
  1. 路由参数:
  • const productId = useParams();:使用钩子检索路由参数useParams
  1. 获取产品数据的函数:
  • getProductById(productId): 定义一个函数getProductById,使用 Axios 根据提供的产品 ID 获取产品数据。
  1. 效果钩子:
  • useEffect(() => { ... }, [productId]);当值发生变化时,执行效果函数productId。它会根据变化的值productId使用该getProductById函数获取产品数据。
  1. 组件 JSX:
  • 显示产品详情,包括标题、图片、评分、价格、描述以及添加到购物车和愿望清单/从购物车移除的按钮。
  1. 出口:
  • export default SingleProductCard;:将该SingleProductCard组件导出为默认导出项。

总而言之,该SingleProductCard组件会根据从路由参数中获取的产品 ID 来获取并显示单个产品的详细信息。它还提供了将产品添加到购物车和愿望清单/从愿望清单中移除的选项。

屏幕输出如下:

图片描述

购物车管理页面

任何电子商务应用程序中的购物车管理器都非常重要,因为它可以帮助用户完全管理商品数量并下单购买。

在这个应用程序中,您可以增加和减少数量,从购物车中移除产品,将产品添加到愿望清单并下单。

以下是示例代码




import { Link, useEffect } from "../../Utils/CustomUtils";

import {

Header,

Footer,

TotalPrice,

Spinner,

} from "../../Components/AllComponentIndex";

import {

useCartContext,

useProductDataContext,

useWishlistContext,

} from "../../Context/AllContextIndex";

import { removeFromCart, updateQty } from "../../Services/CartServices";

import { addToWishlist, deleteWishList } from "../../Services/WishlistServices";

function CartPage() {

const { dispatch, wish } = useWishlistContext();

const { isLoading } = useProductDataContext();

const { cart, state, totalprice } = useCartContext();

useEffect(() => {

dispatch({

type: "TOTALPRICE",

payload: cart.reduce(

(acc, item) => acc + Number(item.qty) * Number(item.price),

0

),

});

}, [cart]);

return (

<>

<Header cart={cart} />

<section class=" bg-gray-100 py-12 sm:py-16 lg:py-20 mb-20">

<div class="mx-auto px-4 sm:px-6 lg:px-8">

<div class="flex items-center justify-center">

</div>

<div class="mx-auto mt-20 mb-8 max-w-2xl md:mt-12">
<div class="bg-white shadow">

<div class="px-4 py-6 sm:px-8 sm:py-10">

<div class="flow-root">

<ul class="-my-8">

{cart.map(cartdata => {

return (

<li class="flex flex-col space-y-3 py-6 text-left sm:flex-row sm:space-x-5 sm:space-y-0">

<div class="shrink-0">

<img class="h-24 w-24 max-w-full rounded-lg object-cover" src={cartdata.image} alt="" />

</div>
<div class="relative flex flex-1 flex-col justify-between">

<div class="sm:col-gap-5 sm:grid sm:grid-cols-2">

<div class="pr-8 sm:pr-5">

<p class="text-base font-semibold text-gray-900">{cartdata.title}</p>

<span class="relative inline-block px-3 py-1 font-semibold text-green-900 leading-tight">

{wish.some(

(wishlist) => wishlist._id === cartdata._id

) ? (

<button data-tooltip-target="tooltip-default"

onClick={(_id) =>

deleteWishList(cartdata._id, dispatch)

}

>

<span class="material-icons">

heart_broken

</span>

</button>

) : (

<button

onClick={() => addToWishlist(cartdata, dispatch)}

>

<span class="material-icons">

{" "}

favorite_border{" "}

</span>

</button>

)}

</span>

<span class="relative inline-block px-3 py-1 font-semibold text-green-900 leading-tight">

<button

onClick={(_id) =>

removeFromCart(cartdata._id, dispatch)

}

>

<span class="material-icons">delete</span>

</button>

</span>

</div>

<div class="mt-4 flex items-end justify-between sm:mt-0 sm:items-start sm:justify-end">

<p class="shrink-0 w-20 text-base font-semibold text-gray-900 sm:order-2 sm:ml-8 sm:text-right">{cartdata.price}</p>

<div class="sm:order-1">

<div class="mx-auto flex h-8 items-stretch text-gray-600">

<button class="flex items-center justify-center rounded-l-md bg-gray-200 px-4 transition hover:bg-black hover:text-white" onClick={() =>

updateQty("decrement", cartdata._id, dispatch)

}>-</button>

<div class="flex w-full items-center justify-center bg-gray-100 px-4 text-xs uppercase transition">{cartdata.qty}</div>

<button class="flex items-center justify-center rounded-r-md bg-gray-200 px-4 transition hover:bg-black hover:text-white" onClick={() =>

updateQty("increment", cartdata._id, dispatch)

}>+</button>

</div>

</div>

</div>

</div>

</div>

</li>)

})

}

</ul>

</div>
<div class="mt-6 border-t border-b py-2">

<div class="flex items-center justify-between">

<p class="text-sm text-gray-400">Subtotal</p>

<p class="text-lg font-semibold text-gray-900">{totalprice}</p>

</div>

</div>

<div class="mt-6 flex items-center justify-between">

<p class="text-sm font-medium text-gray-900">Total</p>

<p class="text-2xl font-semibold text-gray-900"><span class="text-xs font-normal text-gray-400"></span> {totalprice}</p>

</div>
<div class="mt-6 text-center">

<Link to='/Checkoutpage'>

<button type="button" class="group inline-flex w-full items-center justify-center rounded-md bg-gray-900 px-6 py-4 text-lg font-semibold text-white transition-all duration-200 ease-in-out focus:shadow hover:bg-gray-800">

Checkout

<svg xmlns="http://www.w3.org/2000/svg" class="group-hover:ml-8 ml-4 h-6 w-6 transition-all" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">

<path stroke-linecap="round" stroke-linejoin="round" d="M13 7l5 5m0 0l-5 5m5-5H6" />

</svg>

</button> </Link>

</div>

</div>

</div>

</div>

</div>

</section>

<Footer />

</>

);

}

export default CartPage;



Enter fullscreen mode Exit fullscreen mode

这段代码定义了一个名为 `<shopping-cart>` 的 React 函数式组件CartPage,它代表电子商务应用程序的购物车页面。让我们来分析一下这段代码:

  1. 进口:
  • LinkLink从“../../Utils/CustomUtils”导入路由。

  • useEffect: Importing the useEffect hook from React for side effects.

  • Header, Footer, TotalPrice, Spinner: Importing components from "../../Components/AllComponentIndex".

  • useCartContext, useProductDataContext, useWishlistContext: Importing custom hooks from "../../Context/AllContextIndex" for accessing context data related to the cart, product data, and wishlist.

  • removeFromCart, updateQty, addToWishlist, deleteWishList: Importing functions from "../../Services/CartServices" and "../../Services/WishlistServices" for managing cart and wishlist actions.

  1. Function Definition:
  • function CartPage() { ... }: Defines a functional component named CartPage.
  1. Context and State Variables:
  • Retrieves context and state variables using custom context hooks: useWishlistContext, useProductDataContext, useCartContext.

  • Destructures variables like dispatch, wish, isLoading, cart, state, totalprice from the respective contexts.

  1. Effect Hook:
  • Uses the useEffect hook to calculate the total price of items in the cart whenever the cart state changes. It dispatches an action to update the total price.
  1. Component JSX:
  • Renders the header, which includes a cart icon indicating the number of items in the cart.

  • Displays a section for the shopping cart items, including product image, title, price, quantity, and buttons for removing items from the cart or wishlist.

  • Calculates and displays the subtotal and total price of the items in the cart.

  • Provides a "Checkout" button linked to the Checkout page using the Link component.

  1. Export:
  • export default CartPage;: Exports the CartPage component as the default export.

In summary, the CartPage component renders the contents of the shopping cart, and allows users to update quantities, remove items, and proceed to checkout. It also interacts with the wishlist, allowing users to add or remove items.

The cart manager screen output is here :

1711683292669

Wishlist page

The wishlist page allows users to add products for future reffernce hereis the sample code .




import { React } from "../../Utils/CustomUtils";

import {

useProductDataContext,

useWishlistContext,

} from "../../Context/AllContextIndex";

import {

Footer,

Header,

ProductCard,

Spinner,

} from "../../Components/AllComponentIndex";



import "./Wishlist.css";

function WishlistPage() {

const { wish } = useWishlistContext();

const { isLoading } = useProductDataContext();



return (

<div>

<Header />



{isLoading ? (

<Spinner />

) : wish.length === 0 ? (

<div className="cart-mesg"> there are no items in Wishlist </div>

) : (

<div className="wishlist-cards">

{wish.map((wishlistpagedata) => {

return (

<ProductCard

productCardData={wishlistpagedata}

key={wishlistpagedata._id}

/>

);

})}

</div>

)}



<Footer />

</div>

);

}



export default WishlistPage;



Enter fullscreen mode Exit fullscreen mode

This code defines a React functional component named WishlistPage, which represents the wishlist page of an e-commerce application. Here's a breakdown of the code:

  1. Imports:
  • React: Importing the React object from "../../Utils/CustomUtils".

  • useProductDataContext, useWishlistContext: Importing custom hooks from "../../Context/AllContextIndex" for accessing context data related to product data and wishlist.

  • Footer, Header, ProductCard, Spinner: Importing components from "../../Components/AllComponentIndex".

  1. Function Definition:
  • function WishlistPage() { ... }: Defines a functional component named WishlistPage.
  1. Context and State Variables:
  • Retrieves context variables using custom context hooks: useWishlistContext and useProductDataContext.

  • Destructures variables like wish and isLoading from the respective contexts.

  1. Component JSX:
  • Renders the header component.

  • Checks if data is loading. If loading, it displays a spinner component (Spinner).

  • If the wishlist is empty (wish.length === 0), it displays a message indicating that there are no items in the wishlist.

  • If the wishlist is not empty, it maps through each item in the wishlist (wish) and renders a ProductCard component for each item.

  1. CSS Styling:
  • Applies CSS styles defined in the "Wishlist.css" file.
  1. Export:
  • export default WishlistPage;: Exports the WishlistPage component as the default export.

In summary, the WishlistPage component renders the contents of the wishlist. If the wishlist is empty, it displays a message. Otherwise, it renders each item in the wishlist using the ProductCard component.

The Wishlist page output is here :

图片描述

Checkout page

The checkout page is the page where we place actual details and give the consent to place the order in this project the page allows users to see what they are about to purchase under how much quantity and what the total cost to be paid, add an address to enable payments(testing mode) and then only the order will be placed here is the code.




import React from "react";

import {

Footer,

Header,

Checkout,

Spinner,

} from "../../Components/AllComponentIndex";

import { useProductDataContext } from "../../Context/ProductListingPageContext";



import "./Checkoutpage.css";

function Checkoutpage() {

const { isLoading } = useProductDataContext();

return (

<div>

<Header />

{isLoading ? <Spinner /> : <Checkout />}

<Footer />

</div>

);

}

export default Checkoutpage;



Enter fullscreen mode Exit fullscreen mode

This code defines a React functional component named Checkoutpage, which represents the checkout page of an e-commerce application. Let's break down the code:

  1. Imports:
  • React: Importing the React object from "react".

  • Footer, Header, Checkout, Spinner: Importing components from "../../Components/AllComponentIndex".

  • useProductDataContext: Importing a custom hook from "../../Context/ProductListingPageContext" to access context data related to product listing.

  1. Function Definition:
  • function Checkoutpage() { ... }: Defines a functional component named Checkoutpage.
  1. Context and State Variables:
  • Retrieves context variables using the custom hook useProductDataContext.

  • Destructures the isLoading variable from the context.

  1. Component JSX:
  • Renders the header component.

  • Checks if data is loading. If loading, it displays a spinner component (Spinner).

  • If data is not loading, it renders the checkout component (Checkout).

  • Renders the footer component.

  1. CSS Styling:
  • Applies CSS styles defined in the "Checkoutpage.css" file.
  1. Export:
  • export default Checkoutpage;: Exports the Checkoutpage component as the default export.

In summary, the Checkoutpage component renders the checkout page of the e-commerce application. It first displays the header, then either a spinner or the checkout component based on whether data is loading, and finally the footer.

The Checkout page output is here :

图片描述

Order success page

This page shows the order has been placed here is the code.




import React from "react";

import {

Footer,

Header,

OrderConfirm,

Spinner,

} from "../../Components/AllComponentIndex";

import { useProductDataContext } from "../../Context/ProductListingPageContext";



function OrderSuccessPage() {

const { isLoading } = useProductDataContext();

return (

<div>

<Header />

{isLoading ? <Spinner /> : <OrderConfirm />}

<Footer />

</div>

);

}
export default OrderSuccessPage;



Enter fullscreen mode Exit fullscreen mode

This code defines a React functional component named OrderSuccessPage, which represents a page confirming the successful placement of an order. Let's break down the code:

  1. Imports:
  • React: Importing the React object from "react".

  • Footer, Header, OrderConfirm, Spinner: Importing components from "../../Components/AllComponentIndex".

  • useProductDataContext: Importing a custom hook from "../../Context/ProductListingPageContext" to access context data related to the product listing.

  1. Function Definition:
  • function OrderSuccessPage() { ... }: Defines a functional component named OrderSuccessPage.
  1. Context and State Variables:
  • Retrieves context variables using the custom hook useProductDataContext.

  • Destructures the isLoading variable from the context.

  1. Component JSX:
  • Renders the header component.

  • Checks if data is loading. If loading, it displays a spinner component (Spinner).

  • If data is not loading, it renders the order confirmation component (OrderConfirm).

  • Renders the footer component.

  1. Export:
  • export default OrderSuccessPage;: Exports the OrderSuccessPage component as the default export.

In summary, the OrderSuccessPage component renders a page confirming the successful placement of an order. It displays the header, followed by either a spinner or the order confirmation component based on whether data is loading, and finally the footer.

The Order Sucess page output is here :

图片描述

Profile manager page

The profile manager page shows the profile data, purchased product details and already added address here is the code




import React from "react";

import {

Footer,

AccountTabs,

Header,

Spinner,

} from "../../Components/AllComponentIndex";

import { useProductDataContext } from "../../Context/ProductListingPageContext";

import "./AccountPage.css";


function AccountPage() {

const { isLoading } = useProductDataContext();

return (

<div>

<Header />

{isLoading ? <Spinner /> : <AccountTabs />}

<Footer />

</div>

);

}

export default AccountPage;



Enter fullscreen mode Exit fullscreen mode

This code defines a React functional component named AccountPage, which represents a page for managing user accounts. Let's break down the code:

  1. Imports:
  • React: Importing the React object from "react".

  • Footer, AccountTabs, Header, Spinner: Importing components from "../../Components/AllComponentIndex".

  • useProductDataContext: Importing a custom hook from "../../Context/ProductListingPageContext" to access context data related to the product listing.

  • ./AccountPage.css: Importing a CSS file for styling this component.

  1. Function Definition:
  • function AccountPage() { ... }: Defines a functional component named AccountPage.
  1. Context and State Variables:
  • Retrieves context variables using the custom hook useProductDataContext.

  • Destructures the isLoading variable from the context.

  1. Component JSX:
  • Renders the header component.

  • Checks if data is loading. If loading, it displays a spinner component (Spinner).

  • If data is not loading, it renders the account tabs component (AccountTabs), which presumably contains different tabs for managing user account information.

  • Renders the footer component.

  1. Export:
  • export default AccountPage;: Exports the AccountPage component as the default export.

In summary, the AccountPage component renders a page for managing user accounts. It displays the header, followed by either a spinner or the account tabs component based on whether data is loading, and finally the footer. The specific functionality of the account tabs is handled by the AccountTabs component.

The Profile Manager page output is here :

图片描述

Authentication Pages:

The authentication pages are the most important part of any application as they allow the users to register on the platform and later log into the system with valid credentials.

It also helps to track the registered user data by providing a better user experience.

My application has two authentication pages one is a Signup page and another is a Login page, each page has different input types for user signup they will have to provide their name and email along with all these they also have to make a secure password that can be later used for login.

The Login page only accepts two inputs one is your registered email which you had used for the signup and the same registered password.

You can check both of screen output here :

Login Page

图片描述

The Login page also has a Guest Login feature which will take you into the application without registering on the platform.

Signup Page

图片描述

Summary

  1. 我遵循了整洁代码架构,因为它能让我以更清晰的方式展示代码,使其易于理解和维护。

  2. 我遵循标准的文件夹结构来维护代码,并将其分成更小的模块。

  3. 完整的编码遵循函数式编程理念。

  4. 我不是做 UI/UX 的,我的目的是通过构建项目来更好地理解 React JS,所以我在开发时并没有过多关注 UI/UX 部分。

感谢阅读,您可以在GitHub上查看完整代码,也可以在这里浏览项目。

如果您有任何想与我分享的内容,或者希望我开发一些网页应用,我始终乐于接受各种机会。您可以通过领英与我联系

文章来源:https://dev.to/prankurpandeyy/ultimate-guide-to-building-an-e-commerce-store-with-react-js-and-mock-apis-2c7i