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 /team→TeamPage(팀원 소개)URL /login→LoginPage(로그인)
🏫 Visible Thinking: 리액트의 지도 (Map)
이제 수강생들은 웹을 볼 때 아래와 같은 계층 구조로 보게 됩니다.
- Level 1 (The Shell):
index.html(모든 것이 시작되는 빈 그릇) - Level 2 (The Brain):
App.tsx&Router(길을 안내하는 뇌) - Level 3 (The Frame):
Layout(변하지 않는 뼈대 - Header, Footer) - Level 4 (The Scene):
Page(장면 전환 - TeamPage, Home) - Level 5 (The Brick):
Component&Hook(실제 부품과 기능)
🛠️ 실습: 라우터로 웹 서비스 지도 그리기
1. 프로젝트 시작하기 (Vite + VS Code)
'폴더를 먼저 만들고 그 안에서 시작하는 방식'을 사용합니다. 이 방식은 경로를 헷갈릴 염려가 없어 가장 추천하는 방식입니다.
- 폴더 만들고 열기: VS Code를 실행하고 Open Folder를 누릅니다. 파일 선택 창에서 바로
my-team-site라는 새 폴더를 만들고 선택해서 엽니다. - Terminal 열기: 상단 메뉴에서
Terminal->New Terminal을 클릭합니다. - 명령어 입력: 아래 명령어를 순서대로 입력합니다.
# 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가 가장 잘하는 영역입니다.
- 터미널에 아래 명령어를 입력해 Tailwind v4를 설치하고,
- 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 프롬프트 (설계 철학 주입): "나는 지금 팀 소개 웹사이트를 만들고 있어. 너는 내 아키텍처 가이드라인을 따라야 해.
- 모든 화면은
Layout컴포넌트 안의Outlet을 통해 교체되는 중첩 라우팅(Nested Routing) 구조로 설계할 거야.- 스타일은 Tailwind CSS v4를 사용하고 (
vite.config.ts설정 포함), 모든 컴포넌트는 TypeScript로 작성해줘.- 내 폴더 구조는
src/components,src/pages,src/hooks로 나뉘어 있어. 이해했니?"
Step 3. 명세서 및 다이어그램 작성 (Human + AI)
이제 구체적으로 어떤 앱을 만들지 AI와 함께 정의합니다.
- 활동: AI와 대화하며 팀원 데이터(이름, 역할, 한마디 등)가 포함된
prd.md를 작성하세요. - 설계: 주소 이동 흐름을 담은
sequence_diagram.md를 요청하세요.
🤖 AI 프롬프트 (명세 요청): "위 구조를 바탕으로 '팀 소개 페이지'를 위한 요구사항 명세서(prd.md)를 써줘.
- 메인 홈(인사말)과 팀원 목록(카드 형태) 페이지가 포함되어야 해.
- 데이터 구조를 보여주는 Mermaid
class_diagram.md도 작성해줘.- 그리고 사용자가 메뉴를 클릭했을 때
Router와Outlet이 어떻게 작동하는지 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)
화면이 떴다면 다음을 확인하세요:
- 메뉴를 클릭할 때 새로고침 없이 알맹이(Outlet)만 바뀌는가? (브라우저 상단의 새로고침 아이콘이 돌지 않아야 합니다)
- 브라우저 주소창이
/에서/team으로 정확히 변경되는가?
에러가 났나요? 당황하지 마세요. 에러 메시지를 복사해 AI에게 던지며 "설계도와 비교해서 틀린 부분만 고친 전체 코드를 줘"라고 말하세요. 이것이 AI 시대의 디버깅입니다.
🏫 수업 마무리: 우리는 무엇을 배웠나?
- Thinking in React: 웹을 페이지가 아닌 부품(Component)과 지도(Router)로 보는 법.
- Architect's Power: 코드를 직접 치는 노동에서 벗어나, 구조를 설계하고 AI를 제어하는 능력.
- The Flow: URL 입력 → Router 판단 → Layout 렌더링 → Outlet에 Page 주입으로 이어지는 SPA(Single Page App)의 원리.
이제 여러분은 어떤 복잡한 요구사항도 [기획(PRD) → 설계(Diagram) → AI 구현] 프로세스로 해결할 수 있는 AI Native 아키텍트입니다! 🎉