React로 프로덕션 레디 이커머스 플랫폼 구축: 완전 가이드

발행: (2025년 12월 20일 오후 07:34 GMT+9)
6 min read
원문: Dev.to

Source: Dev.to

위에 제공된 소스 링크 아래에 번역하고 싶은 텍스트를 붙여 주세요.
텍스트를 제공해 주시면, 원본 형식과 마크다운을 그대로 유지하면서 한국어로 번역해 드리겠습니다.

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

각 컨텍스트는 단일 책임을 담당하여 컴포넌트를 집중화하고, 재사용 가능하며, 이해하기 쉽게 합니다.

Technology Choices

기술선택한 이유대안
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("");

  // 입력 디바운스
  useEffect(() => {
    const timer = setTimeout(() => setDebouncedQuery(query), 300);
    return () => clearTimeout(timer);
  }, [query]);

  // 디바운스된 쿼리가 바뀔 때 결과 가져오기
  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="제품을 검색하세요..."
      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) : [];
  });

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

  // 탭 간 동기화
  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";
  });

  // 테마 클래스 적용 및 저장
  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;

제품 카드 (메모이제이션)

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

Deployment

vercel --prod

Vercel은 빌드, 프리뷰, 라우팅 및 성능을 기본적으로 처리합니다.

Production Tips

  • 탭 간 장바구니 동기화는 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

관련 글

더 보기 »