React

React 쇼핑몰 구조 이해하기 1편 - 프로젝트 구조와 앱의 시작점


쇼핑몰 코드를 처음 보면 복잡해 보이죠? 상품 목록, 상세 페이지, 장바구니, 게시판까지… 이 코드들이 어떻게 연결되어 있는지 파악하기 어려울 수 있어요.

이 시리즈에서는 이미 완성된 과일 쇼핑몰 예제코드를 함께 분석하면서 React 쇼핑몰의 전체 구조를 이해해볼 거예요. 오늘 1편에서는 프로젝트의 기본 구조를 파악하고, 앱이 어떻게 시작되는지 알아봅니다.

이번 편에서 알아볼 내용

  • ✅ 쇼핑몰 예제코드에서 사용하는 기술 스택
  • ✅ React 앱의 전체 폴더 구조
  • ✅ index.js - React 앱의 시작점
  • ✅ Provider와 BrowserRouter의 역할
  • ✅ App.js - 메인 컴포넌트 구조

이 쇼핑몰에서 사용하는 기술 스택

분석할 쇼핑몰에서는 다음 기술들을 사용해요:

graph LR
    A["React 19"] --> B["React Router v6"]
    A --> C["Redux Toolkit"]
    A --> D["Bootstrap 5"]
    A --> E["Axios"]
    
    style A fill:#61DAFB,color:#000
    style B fill:#CA4245,color:#fff
    style C fill:#764ABC,color:#fff
    style D fill:#7952B3,color:#fff
    style E fill:#5A29E4,color:#fff
기술용도
React 19UI 컴포넌트 개발
React Router v6페이지 간 이동
Redux Toolkit전역 상태 관리 (장바구니)
Bootstrap 5빠른 UI 스타일링
Axios외부 데이터 요청

프로젝트 생성하기

이 프로젝트를 직접 만들어보려면 다음 순서로 진행하세요:

# 1. 프로젝트 생성
npx create-react-app shop

# 2. 폴더 이동
cd shop

# 3. 필요한 라이브러리 설치
npm install react-router-dom @reduxjs/toolkit react-redux bootstrap react-bootstrap axios

# 4. 개발 서버 실행
npm start

프로젝트 폴더 구조

쇼핑몰 프로젝트를 열면 이런 구조가 보여요:

shop/
├── public/
│   ├── img/              # 상품 이미지들
│   │   ├── fruit1.jpg ~ fruit9.jpg
│   │   └── veggie/
│   │       └── veggie1.jpg ~ veggie3.jpg
│   └── index.html
├── src/
│   ├── components/       # 화면을 구성하는 컴포넌트들
│   │   ├── Products.js      # 상품 카드
│   │   ├── Detail.js        # 상품 상세
│   │   ├── Cart.js          # 장바구니
│   │   ├── BoardList.js     # 게시판 목록
│   │   └── ...
│   ├── db/               # 상품 데이터
│   │   ├── fruit.js         # 과일 데이터
│   │   └── veggie.js        # 채소 데이터
│   ├── App.js            # ⭐ 메인 컴포넌트
│   ├── store.js          # ⭐ Redux 상태 저장소
│   └── index.js          # ⭐ 앱 시작점
└── package.json

⭐ 표시된 파일이 가장 중요한 핵심 파일들이에요!

앱의 시작 흐름 이해하기

React 앱이 브라우저에서 어떻게 실행되는지 순서대로 살펴볼게요:

graph TD
    A["index.html<br/>(빈 HTML 파일)"] --> B["index.js<br/>(React 진입점)"]
    B --> C["Provider 감싸기<br/>(Redux 연결)"]
    C --> D["BrowserRouter 감싸기<br/>(라우팅 활성화)"]
    D --> E["App.js<br/>(실제 화면 렌더링)"]
    
    style A fill:#e1f5ff
    style B fill:#ffe1e1
    style C fill:#e1d5ff
    style D fill:#fff4e1
    style E fill:#e1ffe1

하나씩 자세히 볼게요!

index.js - 앱의 시작점

src/index.js 파일은 이렇게 생겼어요:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import {BrowserRouter} from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './store';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>
);

코드를 하나씩 뜯어볼게요:

1. Import 부분

import {BrowserRouter} from 'react-router-dom';  // 라우팅
import { Provider } from 'react-redux';          // Redux 연결
import store from './store';                     // 우리가 만든 store

2. Provider - Redux 연결하기

<Provider store={store}>
  ...
</Provider>

Provider는 Redux 상태를 앱 전체에서 사용할 수 있게 해줘요. 마치 전기 콘센트에 플러그를 꽂는 것처럼, 앱에 Redux를 “꽂아주는” 역할이에요.

store는 장바구니 같은 전역 데이터를 저장하는 곳이에요. 4편에서 자세히 알아볼 거예요!

3. BrowserRouter - 라우팅 활성화

<BrowserRouter>
  <App />
</BrowserRouter>

BrowserRouter로 감싸야 URL에 따라 다른 페이지를 보여줄 수 있어요:

  • / → 홈 (상품 목록)
  • /detail/1 → 1번 상품 상세
  • /cart → 장바구니
  • /board → 게시판

왜 이렇게 감싸는 걸까?

graph TB
    subgraph "감싸는 순서 (바깥 → 안쪽)"
        P["Provider<br/>(Redux 상태 전달)"]
        B["BrowserRouter<br/>(URL 라우팅)"]
        A["App<br/>(실제 화면)"]
        P --> B --> A
    end
    
    style P fill:#e1d5ff
    style B fill:#fff4e1
    style A fill:#e1ffe1

비유로 설명하면:

  • Provider = 전기 콘센트 (상태라는 전기를 공급)
  • BrowserRouter = 건물 복도 (어느 방으로 갈지 안내)
  • App = 실제 방 (화면에 보이는 내용)

App.js - 메인 컴포넌트 구조

이제 src/App.js를 볼게요. 이 파일이 쇼핑몰의 실제 화면을 담당해요.

전체 구조 미리보기

graph TD
    subgraph App["App.js"]
        N["Navbar<br/>(상단 메뉴)"]
        R["Routes<br/>(페이지 라우팅)"]
    end
    
    R --> Home["/ (홈)<br/>상품 목록"]
    R --> Detail["/detail/:id<br/>상품 상세"]
    R --> Cart["/cart<br/>장바구니"]
    R --> About["/about<br/>회사소개"]
    R --> Board["/board<br/>게시판"]
    
    style App fill:#f8f9fa
    style N fill:#343a40,color:#fff
    style Home fill:#e1ffe1
    style Detail fill:#e1f5ff
    style Cart fill:#ffe1e1
    style About fill:#fff4e1
    style Board fill:#e1d5ff

Import 부분

import { useState } from "react";
import "./App.css";
import { Navbar, Container, Nav, Button } from "react-bootstrap";
import data from "./db/fruit";
import Products from "./components/Products";
import { Routes, Route, useNavigate } from "react-router-dom";
import Detail from "./components/Detail";
import Cart from "./components/Cart";
// ... 더 많은 import

여기서 중요한 것들:

  • useState - 상태를 관리하는 React Hook
  • react-bootstrap - 이쁜 UI 컴포넌트들
  • data from "./db/fruit" - 과일 상품 데이터
  • Routes, Route, useNavigate - 페이지 이동 도구

상태(State) 정의

App.js에서 관리하는 상태들을 살펴볼게요:

function App() {
  // 과일 상품 데이터
  const [fruit, setFruit] = useState(data);
  
  // 채소 상품 데이터
  let [veggie, setVeggie] = useState(data2);
  
  // 더 보기 버튼 클릭 횟수
  let [count, setCount] = useState(1);
  
  // 검색어 입력값
  let [input, setInput] = useState("");
  
  // 게시판 글 목록
  const [posts, setPosts] = useState([
    {
      id: 1,
      title: "사과는 언제 배송이 되나요?",
      content: "어제부터 기다렸는데 아직 배송이 안됐어요.",
      author: "김과일",
      date: new Date().getTime(),
      views: 1,
    },
    // ...
  ]);
  
  const navigate = useNavigate();
  // ...
}
<Navbar bg="dark" variant="dark">
  <Container>
    <Navbar.Brand onClick={() => navigate("/")}>
      과일농장
    </Navbar.Brand>
    <Nav className="me-auto">
      <Nav.Link onClick={() => navigate("/")}>홈으로</Nav.Link>
      <Nav.Link onClick={() => navigate("/detail/1")}>상세페이지</Nav.Link>
      <Nav.Link onClick={() => navigate("/cart")}>장바구니</Nav.Link>
      <Nav.Link onClick={() => navigate("/about")}>회사소개</Nav.Link>
      <Nav.Link onClick={() => navigate("/board")}>게시판</Nav.Link>
    </Nav>
  </Container>
</Navbar>

useNavigate를 사용하면 클릭했을 때 다른 페이지로 이동할 수 있어요.

Routes - 페이지 라우팅

<Routes>
  {/* 홈 페이지 */}
  <Route path="/" element={<div>... 상품 목록 ...</div>} />
  
  {/* 상품 상세 */}
  <Route path="/detail/:paramId" element={<Detail fruit={fruit} veggie={veggie} />} />
  
  {/* 장바구니 */}
  <Route path="/cart" element={<Cart />} />
  
  {/* 회사소개 (중첩 라우팅) */}
  <Route path="/about" element={<About />}>
    <Route path="member" element={<Member />} />
    <Route path="location" element={<Location />} />
  </Route>
  
  {/* 게시판 */}
  <Route path="/board" element={<BoardList posts={posts} ... />} />
  <Route path="/board/write" element={<BoardWrite onAdd={handleAddPost} />} />
  <Route path="/board/:id" element={<BoardDetail posts={posts} ... />} />
  <Route path="/board/edit/:id" element={<BoardEdit posts={posts} ... />} />
  
  {/* 404 페이지 */}
  <Route path="/*" element={<NotFound />} />
</Routes>

여기서 핵심 포인트:

  • path="/" - URL이 /이면 이 컴포넌트를 보여줘
  • :paramId - 동적 파라미터 (1, 2, 3 등 어떤 값이든 받음)
  • element={<컴포넌트 />} - 해당 URL에서 보여줄 컴포넌트

정리

오늘 1편에서 살펴본 내용을 정리하면:

graph LR
    A["index.js"] --> B["Provider<br/>(Redux 연결)"]
    B --> C["BrowserRouter<br/>(라우팅)"]
    C --> D["App.js<br/>(Navbar + Routes)"]
    
    style A fill:#ffe1e1
    style B fill:#e1d5ff
    style C fill:#fff4e1
    style D fill:#e1ffe1

핵심 포인트:

  1. 📦 index.js는 앱의 시작점이고, Provider와 BrowserRouter로 App을 감싼다
  2. 🔌 Provider는 Redux 상태를 앱 전체에 공급한다
  3. 🛣️ BrowserRouter는 URL에 따라 다른 화면을 보여준다
  4. 📱 App.js는 Navbar(상단메뉴)와 Routes(페이지들)로 구성된다

다음 편에서는 상품 목록이 화면에 어떻게 표시되는지, 검색과 정렬은 어떻게 동작하는지 알아볼게요!