Building a Production-Ready E-Commerce Platform with React: A Complete Walkthrough
Source: Dev.to
TL;DR
I built a complete e-commerce frontend called ShopStyle using React 18, Tailwind CSS, and modern patterns. It features real‑time search, a persistent cart, dark mode, and 60 fps animations. This article breaks down the architecture, challenges, and key decisions.
Live Demo: https://shopstyle-demo.example.com
Source Code: https://github.com/yourusername/shopstyle
Goals
- Create a realistic shopping experience with real product data.
- Implement modern React patterns (not just another Todo app).
- Target a 95+ Lighthouse performance score.
- Deliver a beautiful UI with smooth animations and responsive design.
- Keep the code maintainable with a clean architecture.
What I Built
- Real‑time search powered by the DummyJSON API.
- Persistent shopping cart (localStorage + cross‑tab sync).
- Dark / light mode with system‑preference detection.
- 60 fps animations using Framer Motion.
- Fully responsive, mobile‑first layout.
- Performance‑optimized (95+ Lighthouse score).
Architecture Overview
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
Each context handles a single responsibility, keeping components focused, reusable, and easy to reason about.
Technology Choices
| Technology | Why I Chose It | Alternatives |
|---|---|---|
| React 18 | Stable ecosystem, concurrent features | Vue, Svelte |
| Vite | Lightning‑fast developer experience | Create React App |
| Tailwind CSS | Speed + consistency | Styled Components |
| Context API | Perfect for mid‑size apps | Redux, Zustand |
| Framer Motion | Declarative animations | React Spring |
| DummyJSON | Realistic fake data | MSW (Mock Service Worker) |
Key Code Snippets
Search Bar (real‑time, debounced)
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;
Persistent Cart (localStorage + cross‑tab sync)
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;
Theme Management (dark / light)
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;
Product Card (memoized)
import { memo } from "react";
const ProductCard = memo(({ product }) => {
return {product.title};
});
export default ProductCard;
Virtualized Product List (react‑window)
import { FixedSizeList as List } from "react-window";
const VirtualProductList = ({ products }) => (
{({ index, style }) => (
)}
);
Lighthouse Scores
| Metric | Score |
|---|---|
| Performance | 96 |
| Accessibility | 100 |
| Best Practices | 100 |
| SEO | 92 |
Deployment
vercel --prod
Vercel handles builds, previews, routing, and performance out of the box.
Production Tips
- Cart sync across tabs relies on
storageevents. - Keep animations limited to
transformandopacityfor optimal frame rates. - Always plan for API failures and implement caching strategies.
Backend & Extras (future work)
- Node + PostgreSQL API
- Stripe integration for payments
- PWA support
- Internationalization
Getting Started
git clone https://github.com/yourusername/shopstyle.git
cd shopstyle
npm install
npm run dev
Closing Thoughts
Huge thanks to React, Tailwind, DummyJSON, and the DEV community ❤️
- ⭐ Star the repository
- Happy coding — the best project is the one you actually finish. 🚀