使用 React 构建生产就绪的电子商务平台:完整指南

发布: (2025年12月20日 GMT+8 18:34)
5 min read
原文: Dev.to

I’m happy to translate the article for you, but I don’t have access to the content of the linked page. Could you please paste the text you’d like translated (excluding any code blocks or URLs you want to keep unchanged)? Once you provide it, I’ll translate it into Simplified Chinese while preserving the original formatting.

TL;DR

我使用 React 18、Tailwind CSS 和现代模式构建了一个完整的电商前端,名为 ShopStyle。它具备实时搜索、持久化购物车、暗黑模式以及 60 fps 动画。本文将拆解其架构、挑战和关键决策。

Live Demo: https://shopstyle-demo.example.com
Source Code: https://github.com/yourusername/shopstyle

目标

  • 创建一个使用真实产品数据的真实购物体验。
  • 实现现代 React 模式(不仅仅是另一个 Todo 应用)。
  • 目标 Lighthouse 性能得分 95+。
  • 提供美观的 UI,具备流畅动画和响应式设计。
  • 保持代码可维护,采用清晰的架构。

我构建的内容

  • 实时搜索,使用 DummyJSON API 提供动力。
  • 持久化购物车(localStorage + 跨标签页同步)。
  • 深色 / 浅色模式,支持系统偏好检测。
  • 使用 Framer Motion 的 60 fps 动画。
  • 完全响应式,移动优先布局。
  • 性能优化(Lighthouse 分数 95+)。

架构概览

graph TB
    A[App.jsx] --> B[ThemeContext]
    A --> C[ProductContext]
    A --> D[CartContext]

    C --> E[ProductList]
    E --> F[ProductCard]

    D --> G[CartSidebar]
    D --> F

    H[SearchBar] --> I((DummyJSON API))
    I --> C

    B --> A

每个 context 只处理单一职责,使组件保持专注、可复用且易于理解。

技术选择

技术我选择它的原因替代方案
React 18稳定的生态系统,支持并发特性Vue, Svelte
Vite极速的开发者体验Create React App
Tailwind CSS快速且一致Styled Components
Context API适合中型应用的完美选择Redux, Zustand
Framer Motion声明式动画React Spring
DummyJSON逼真的假数据MSW (Mock Service Worker)

关键代码片段

搜索栏(实时,防抖)

import { useState, useEffect } from "react";

const SearchBar = ({ onSearch }) => {
  const [query, setQuery] = useState("");
  const [debouncedQuery, setDebouncedQuery] = useState("");

  // Debounce input
  useEffect(() => {
    const timer = setTimeout(() => setDebouncedQuery(query), 300);
    return () => clearTimeout(timer);
  }, [query]);

  // Fetch results when debounced query changes
  useEffect(() => {
    if (!debouncedQuery.trim()) {
      onSearch(null);
      return;
    }

    const search = async () => {
      try {
        const res = await fetch(
          `https://dummyjson.com/products/search?q=${debouncedQuery}`
        );
        const data = await res.json();
        onSearch(data.products);
      } catch {
        onSearch([]);
      }
    };

    search();
  }, [debouncedQuery, onSearch]);

  return (
     setQuery(e.target.value)}
      placeholder="Search products..."
      className="w-full px-4 py-2 border rounded-lg"
    />
  );
};

export default SearchBar;

持久化购物车(localStorage + 跨标签页同步)

import { useState, useEffect } from "react";

const useCart = () => {
  const [cart, setCart] = useState(() => {
    const stored = localStorage.getItem("shopstyle-cart");
    return stored ? JSON.parse(stored) : [];
  });

  // Persist to localStorage
  useEffect(() => {
    localStorage.setItem("shopstyle-cart", JSON.stringify(cart));
  }, [cart]);

  // Sync across tabs
  useEffect(() => {
    const sync = (e) => {
      if (e.key === "shopstyle-cart") {
        setCart(JSON.parse(e.newValue || "[]"));
      }
    };
    window.addEventListener("storage", sync);
    return () => window.removeEventListener("storage", sync);
  }, []);

  return [cart, setCart];
};

export default useCart;

主题管理(暗色 / 亮色)

import { useState, useEffect, useCallback } from "react";

const useTheme = () => {
  const [theme, setTheme] = useState(() => {
    const saved = localStorage.getItem("shopstyle-theme");
    if (saved) return saved;
    return window.matchMedia("(prefers-color-scheme: dark)").matches
      ? "dark"
      : "light";
  });

  // Apply theme class and persist
  useEffect(() => {
    document.documentElement.className = theme;
    localStorage.setItem("shopstyle-theme", theme);
  }, [theme]);

  const toggleTheme = useCallback(() => {
    setTheme((prev) => (prev === "light" ? "dark" : "light"));
  }, []);

  return { theme, toggleTheme };
};

export default useTheme;

商品卡片(memo化)

import { memo } from "react";

const ProductCard = memo(({ product }) => {
  return {product.title};
});

export default ProductCard;

虚拟化商品列表(react‑window)

import { FixedSizeList as List } from "react-window";

const VirtualProductList = ({ products }) => (
  
    {({ index, style }) => (
      
        
      
    )}
  
);

灯塔分数

指标得分
性能96
可访问性100
最佳实践100
SEO92

部署

vercel --prod

Vercel 开箱即用地处理构建、预览、路由和性能。

生产提示

  • 选项卡之间的购物车同步依赖 storage 事件。
  • 将动画限制在 transformopacity 以获得最佳帧率。
  • 始终为 API 失败做好计划并实现缓存策略。

后端与扩展(未来工作)

  • Node + PostgreSQL API
  • Stripe 支付集成
  • PWA 支持
  • 国际化

入门

git clone https://github.com/yourusername/shopstyle.git
cd shopstyle
npm install
npm run dev

结束语

衷心感谢 React、Tailwind、DummyJSON 以及 DEV 社区 ❤️

  • ⭐ 给仓库加星
  • 祝编码愉快 — 最好的项目是你真正完成的那个。 🚀
Back to Blog

相关文章

阅读更多 »