콘텐츠로 이동

07. React (Single Page App) 🗺️

리액트 앱은 여러 개의 HTML 파일이 아닙니다. index.html 하나 위에서 장면만 바뀌는 연극, 즉 SPA(Single Page Application)입니다.

💡 핵심 원리: SPA (Single Page App)의 흐름

URL 입력 → Router 판단 → Layout 렌더링 → Outlet에 Page 주입

이 흐름에서 장면 전환을 담당하는 것이 Router이고, 바뀌지 않는 무대 배경이 Layout입니다.

7-0. SPA vs MPA: 왜 새로고침이 없을까? 🤔

전통적인 웹사이트(MPA)와 리액트(SPA)의 가장 큰 차이는 "누가 화면을 바꾸는가"에 있습니다.

A. 전통적인 방식 (MPA: Multi Page Application)

새로운 주소로 갈 때마다 서버에게 "새 종이(HTML) 줘!" 라고 요청합니다. 그때마다 화면이 깜빡입니다.

graph LR
    User("👤 사용자") -->|클릭| Browser
    Browser("🌐 브라우저") -->|"1. 새 HTML 주세요"| Server("🖥️ 서버")
    Server -->|"2. 자, 새 HTML 받으세요"| Browser
    Browser -->|"3. 화면 전체 새로고침 (깜빡!)"| User

B. 리액트 방식 (SPA: Single Page Application)

처음에 딱 한 장의 종이(index.html)만 받아옵니다. 그 다음부터는 브라우저에 살고 있는 자바스크립트(Router)가 화면의 그림만 쓱 바꿉니다.

graph LR
    User("👤 사용자") -->|클릭| Browser("🌐 브라우저")
    Browser -->|"1. 주소만 변경 (요청 X)"| Router("🛤️ Router")
    Router -->|"2. 필요한 컴포넌트만 교체"| Screen("🖼️ 화면")
    Screen -->|"3. 깜빡임 없이 즉시 변경"| User

    style Router fill:#E1F5FE,stroke:#01579B
    style Screen fill:#FFF3E0,stroke:#FF6F00

7-1. 한 눈에 보는 접속 흐름 (Entry Point Sequence)

사용자가 브라우저 주소창에 주소를 입력하는 순간부터 화면이 뜰 때까지의 "바톤 터치" 과정입니다.

sequenceDiagram
    participant User as 👤 사용자
    participant Browser as 🌐 브라우저 (URL)
    participant HTML as 📄 index.html
    participant App as ⚛️ App.tsx (Main)
    participant Router as 🛤️ Router
    participant Page as 🏠 Page (TeamPage)
    participant Component as 🧩 Component (ProfileCard)

    User->>Browser: 1. "clapcampus.kr/team" 입력
    Browser->>HTML: 2. 서버로부터 유일한 파일 'index.html' 로드
    HTML->>App: 3. 리액트 엔진 가동 (App.tsx 실행)
    App->>Router: 4. "/team" 주소에 맞는 페이지 찾아줘!
    Router->>Page: 5. "TeamPage" 너로 정했다! (컴포넌트 호출)
    Page->>Component: 6. 데이터 조립 및 하위 부품 렌더링
    Component-->>User: 7. 최종 화면 출력 🎉

7-2. Layout: 변하지 않는 틀 (Global UI)

모든 페이지에서 반복되는 헤더(Header), 메뉴바(Nav)나 푸터(Footer)를 매번 페이지마다 새로 만드는 것은 낭비입니다. 리액트는 Layout이라는 큰 틀을 만들어 놓고, 가운데 알맹이(Page)만 갈아 끼웁니다.

// src/components/Layout.tsx
import { Outlet } from 'react-router-dom';

function Layout() {
  return (
    <div className="min-h-screen flex flex-col">
      <Header /> {/* 상단 언제나 고정 */}
      <nav><NavBar /></nav> {/* 메뉴 언제나 고정 */}

      <main className="flex-grow">
        <Outlet /> {/* 🔄 여기가 Router에 의해 Page가 바뀌는 지점! */}
      </main>

      <Footer /> {/* 하단 언제나 고정 */}
    </div>
  );
}

7-3. Router: 주소에 생명 불어넣기

react-router-dom 같은 도구를 쓰면, 주소창의 텍스트를 인식해 특정 페이지를 보여줄 수 있습니다.

  • URL /LandingPage (홈 화면)
  • URL /teamTeamPage (팀원 소개)
  • URL /loginLoginPage (로그인)

🏫 Visible Thinking: 리액트의 지도 (Map)

이제 수강생들은 웹을 볼 때 아래와 같은 계층 구조로 보게 됩니다.

  1. Level 1 (The Shell): index.html (모든 것이 시작되는 빈 그릇)
  2. Level 2 (The Brain): App.tsx & Router (길을 안내하는 뇌)
  3. Level 3 (The Frame): Layout (변하지 않는 뼈대 - Header, Footer)
  4. Level 4 (The Scene): Page (장면 전환 - TeamPage, Home)
  5. Level 5 (The Brick): Component & Hook (실제 부품과 기능)

🛠️ 실습: 라우터로 웹 서비스 지도 그리기

1. 프로젝트 시작하기 (Vite + VS Code)

'폴더를 먼저 만들고 그 안에서 시작하는 방식'을 사용합니다. 이 방식은 경로를 헷갈릴 염려가 없어 가장 추천하는 방식입니다.

  1. 폴더 만들고 열기: VS Code를 실행하고 Open Folder를 누릅니다. 파일 선택 창에서 바로 my-team-site라는 새 폴더를 만들고 선택해서 엽니다.
  2. Terminal 열기: 상단 메뉴에서 Terminal -> New Terminal을 클릭합니다.
  3. 명령어 입력: 아래 명령어를 순서대로 입력합니다.
# 1. 현재 폴더(.)에 Vite 프로젝트 생성
# 반드시 뒤에 점(.)을 찍어주세요. "현재 위치에 바로 만들어줘!"라는 뜻입니다.
npm create vite@latest . -- --template react-ts

# 2. 필요한 기본 부품들 설치
npm install

# 3. 오늘의 주인공 '라우터' 라이브러리 추가 설치
npm install react-router-dom

# 4. 개발 서버 실행
npm run dev

왜 점(.)을 찍나요?

폴더를 미리 만들고 들어왔기 때문에, 또 폴더를 만들 필요가 없기 때문입니다. 이렇게 하면 cd my-team-site 같은 이동 명령어를 생략할 수 있어 훨씬 실수가 적습니다.

GitHub 연동 타임라인

npm install이 끝나면, 왼쪽 Source Control 아이콘을 눌러 Publish to GitHub를 진행해주세요. 그래야 작업 중간중간 안전하게 커밋을 남길 수 있습니다.


2. 폴더 구조 잡기 (Architecture)

src 폴더 안에 아래 두 폴더를 만들어 역할을 분리합니다.

  • src/pages/: 주소에 따라 바뀌는 '장면' (Home, Team 등)
  • src/components/: 바뀌지 않는 '틀'이나 '부품' (Layout, Header 등)

3. 알맹이와 틀 만들기 (Pages & Components)

이제 화면(Page)부품(Component)을 조립해봅시다. 특히 이번에는 내비게이션 바를 따로 분리해서 '부품화'하는 법을 배웁니다.

3-1. 페이지 만들기 (Pages)

주소에 따라 갈아 끼워질 알맹이들입니다.

// src/pages/HomePage.tsx
export default function HomePage() {
  return <h2 style={{ padding: '20px' }}>🏠 메인 화면입니다.</h2>;
}

// src/pages/TeamPage.tsx
export default function TeamPage() {
  return <h2 style={{ padding: '20px' }}>😎 우리 팀원 소개 화면입니다.</h2>;
}

3-2. 내비게이션 부품 만들기 (NavBar) ⭐

Layout에 직접 코딩하지 않고, NavBar.tsx라는 부품을 따로 만듭니다. 이렇게 하면 나중에 메뉴가 복잡해져도 이 파일만 고치면 됩니다.

// src/components/NavBar.tsx
import { NavLink } from 'react-router-dom';

export default function NavBar() {
  return (
    <nav>
      {/* 시맨틱 태그: 메뉴는 리스트(ul/li)로 묶는 것이 웹 표준입니다. */}
      <ul>
        <li>
          <NavLink to="/"></NavLink>
        </li>
        <li>
          <NavLink to="/team"> 소개</NavLink>
        </li>
      </ul>
    </nav>
  );
}

3-3. 전체 틀 조립하기 (Layout)

이제 Layout.tsx가 훨씬 깔끔해집니다. 아까 만든 <NavBar />를 레고 블록처럼 끼워 넣기만 하면 됩니다.

// src/components/Layout.tsx
import { Outlet } from 'react-router-dom';
import NavBar from './NavBar'; // 👈 우리가 만든 부품 가져오기

export default function Layout() {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', minHeight: '100vh' }}>
      {/* 1. 헤더 (고정) */}
      <header style={{ background: '#2563eb', color: 'white', padding: '1rem' }}>
        <h1>🚀 Clap Campus</h1>
        {/* 복잡한 태그 대신 깔끔하게 NavBar 컴포넌트 사용 */}
        <NavBar /> 
      </header>

      {/* 2. 본문 (갈아 끼워지는 곳) */}
      <main style={{ flexGrow: 1, background: '#f9fafb' }}>
        {/* 🔄 Outlet: 라우터가 페이지를 렌더링하는 '예약석' */}
        <Outlet />
      </main>

      {/* 3. 푸터 (고정) */}
      <footer style={{ textAlign: 'center', padding: '1rem', background: '#eee' }}>
        © 2026 리액트 아키텍트 실습
      </footer>
    </div>
  );
}

4. 지도 완성하기 (App.tsx)

마지막으로 App.tsx에서 모든 것을 연결합니다. 최신 중첩 라우팅 방식을 사용합니다.

// src/App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Layout from './components/Layout';
import HomePage from './pages/HomePage';
import TeamPage from './pages/TeamPage';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        {/* "/" 경로에 Layout을 먼저 배치하고, 그 안의 Outlet 자리에 자식들을 넣습니다. */}
        <Route path="/" element={<Layout />}>
          <Route index element={<HomePage />} /> {/* 기본 화면 */}
          <Route path="team" element={<TeamPage />} /> {/* "/team" 경로 */}
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

export default App;

💡 AI Native Tip: 디자인은 AI에게 맡기세요 (Tailwind CSS v4)

지금 작성한 코드를 실행해보면 기능은 완벽하지만, 디자인이 정말 투박할 겁니다. (이게 정상입니다!) 저희는 '기능 구현(Logic)'에 집중했습니다. '예쁘게 꾸미기(Style)'는 AI가 가장 잘하는 영역입니다.

  1. 터미널에 아래 명령어를 입력해 Tailwind v4를 설치하고,
    npm install tailwindcss @tailwindcss/vite
    
  2. AI에게 이렇게 명령해보세요.

    "지금 내 프로젝트에 Tailwind CSS v4를 적용해주고 (vite.config.ts 수정), NavBar와 Layout을 세련된 모던 스타일로 다시 작성해줘."


🏫 수강생이 꼭 기억해야 할 핵심 원리

💡 Outlet은 '예약석'입니다

  • 작동 방식: 사용자가 /team 주소로 접속하면, 리액트 라우터는 Layout 컴포넌트를 먼저 화면에 띄웁니다. 그리고 Layout 안에 있는 <Outlet /> 태그를 찾아 그 자리에 TeamPage를 쏙 끼워 넣습니다.
  • 장점: 헤더나 푸터는 새로 그려지지 않고 그대로 유지되므로 속도가 매우 빠르고 사용자 경험이 매끄럽습니다.

💡 발음 팁: "라우트" vs "루트"

  • 라우트(Route): 지금 우리가 설정한 주소 경로입니다. (미국식 '라우트' 발음 권장)
  • 루트(Root): 리액트가 뿌리를 내리는 최상위 div(id="root")를 뜻합니다. (발음 '루트')

이제 Frontend 파트의 전체 흐름이 완벽하게 정리되었습니다! 이 실습까지 마치면 수강생들은 "웹 앱의 구조를 설계하고 조립하는 아키텍트"로서의 첫걸음을 떼게 됩니다.


08. [최종 실습] AI 아키텍처: 팀 소개 페이지 구축하기 👥

이제 우리는 단순히 코드를 복사하는 수준을 넘어, 웹 서비스의 전체 지도(Router)와 큰 틀(Layout)을 설계하고 AI에게 구현을 명령합니다.

🛠️ 실습 목표

  • 인간: 서비스 설계(Layout 구조 정의, 데이터 명세, 페이지 흐름 기획)
  • AI: 설계도에 기반한 코드 자동 생성 및 디버깅

Step 1. 프로젝트 기반 다지기 (Human)

VS Code에서 team-introduction-site라는 새 폴더를 만들고 엽니다. 그 후 터미널에서 다음 명령어를 입력하세요.

# 1. 현재 폴더에 프로젝트 생성
npm create vite@latest . -- --template react-ts

# 2. 필수 라이브러리 설치 (Router + Tailwind CSS v4)
npm install react-router-dom
npm install tailwindcss @tailwindcss/vite

Step 2. AI에게 '구조적 가이드라인' 제시하기 (Context Setting)

AI에게 무작정 코드를 요청하지 마세요. 우리가 사용할 고급 기술 구조를 먼저 주입합니다.

🤖 AI 프롬프트 (설계 철학 주입): "나는 지금 팀 소개 웹사이트를 만들고 있어. 너는 내 아키텍처 가이드라인을 따라야 해.

  1. 모든 화면은 Layout 컴포넌트 안의 Outlet을 통해 교체되는 중첩 라우팅(Nested Routing) 구조로 설계할 거야.
  2. 스타일은 Tailwind CSS v4를 사용하고 (vite.config.ts 설정 포함), 모든 컴포넌트는 TypeScript로 작성해줘.
  3. 내 폴더 구조는 src/components, src/pages, src/hooks로 나뉘어 있어. 이해했니?"

Step 3. 명세서 및 다이어그램 작성 (Human + AI)

이제 구체적으로 어떤 앱을 만들지 AI와 함께 정의합니다.

  • 활동: AI와 대화하며 팀원 데이터(이름, 역할, 한마디 등)가 포함된 prd.md를 작성하세요.
  • 설계: 주소 이동 흐름을 담은 sequence_diagram.md를 요청하세요.

🤖 AI 프롬프트 (명세 요청): "위 구조를 바탕으로 '팀 소개 페이지'를 위한 요구사항 명세서(prd.md)를 써줘.

  • 메인 홈(인사말)과 팀원 목록(카드 형태) 페이지가 포함되어야 해.
  • 데이터 구조를 보여주는 Mermaid class_diagram.md도 작성해줘.
  • 그리고 사용자가 메뉴를 클릭했을 때 RouterOutlet이 어떻게 작동하는지 Mermaid 문법으로 sequence_diagram.md를 그려줘."

Step 4. 아키텍트의 최종 명령 (Execution) 🚀

이제 모든 준비가 끝났습니다. 지금까지 합의한 모든 설계 내용을 바탕으로 전체 코드를 생성하게 합니다.

🚀 최종 구현 프롬프트 (복사해서 AI에게 던지세요):

# 역할 부여
당신은 리액트 아키텍처 설계 전문가입니다.
**관심사의 분리(Separation of Concerns)** 원칙을 철저히 지켜 코드를 작성해주세요.

# 구현 목표
팀원 소개 프로필 카드 웹사이트를 만듭니다.
작성된 **기획서**, **설계도**, **와이어프레임**을 모두 참고하여 구현해주세요.

# 참고 자료 (반드시 내용을 확인하고 반영할 것)
1. **기획서:** `prd.md` (첨부파일)
2. **설계도:** `class_diagram.md`, `sequence_diagram.md` (첨부파일)
3. **화면 구성:** `wireframe.png` (첨부한 이미지를 시각적 가이드로 삼을 것)

# 핵심 요구 사항
1. **기능:**
    - 팀원 데이터(이름, 직업, 사진, 온라인여부) 표시
    - "온라인인 사람만 보기" 필터링 기능
2. **디자인:**
    - 와이어프레임의 레이아웃을 준수하세요.
    - Tailwind CSS를 사용하여 깔끔하고 현대적인 스타일로 구현하세요.
3. **라우팅 구조 (반드시 준수):**
    - `src/components/Layout.tsx`를 만들어 Header(Nav)와 Footer를 포함하세요.
    - 리액트 라우터의 **`Outlet`**을 사용하여, URL 변경 시 `Layout` 내부의 콘텐츠만 교체되도록 구현하세요.

# 📂 디렉토리 구조 가이드 (필수 준수)
아래의 폴더 구조 규칙에 맞춰서, **가장 적절한 파일명을 당신이 직접 지어서** 코드를 작성해주세요.
모든 코드 블록의 최상단에는 `// src/hooks/useExample.ts` 처럼 **파일 경로를 주석으로 명시**해야 합니다.

1. **`src/types/`**: 공통 인터페이스 정의
2. **`src/hooks/`**: 데이터(State)와 로직(Filter)을 담당하는 Custom Hook
3. **`src/components/`**: 로직 없이 UI만 담당하는 순수 컴포넌트
4. **`src/pages/`**: Hook과 Component를 조립하는 페이지
5. **`src/App.tsx`**: 위에서 만든 페이지를 불러오는 메인 파일

# 기술 스택
- Vite + React + TypeScript
- Tailwind CSS

Step 5. 검증 및 수정 (The Loop)

화면이 떴다면 다음을 확인하세요:

  1. 메뉴를 클릭할 때 새로고침 없이 알맹이(Outlet)만 바뀌는가? (브라우저 상단의 새로고침 아이콘이 돌지 않아야 합니다)
  2. 브라우저 주소창이 /에서 /team으로 정확히 변경되는가?

에러가 났나요? 당황하지 마세요. 에러 메시지를 복사해 AI에게 던지며 "설계도와 비교해서 틀린 부분만 고친 전체 코드를 줘"라고 말하세요. 이것이 AI 시대의 디버깅입니다.


🏫 수업 마무리: 우리는 무엇을 배웠나?

  1. Thinking in React: 웹을 페이지가 아닌 부품(Component)지도(Router)로 보는 법.
  2. Architect's Power: 코드를 직접 치는 노동에서 벗어나, 구조를 설계하고 AI를 제어하는 능력.
  3. The Flow: URL 입력 → Router 판단 → Layout 렌더링 → Outlet에 Page 주입으로 이어지는 SPA(Single Page App)의 원리.

이제 여러분은 어떤 복잡한 요구사항도 [기획(PRD) → 설계(Diagram) → AI 구현] 프로세스로 해결할 수 있는 AI Native 아키텍트입니다! 🎉