다크 모드
《실전 React 19.3 & TypeScript: jQuery 레거시에서 완성하는 게시판 아키텍처》
사내 개발자를 위한 단일 코드베이스 점진적 리팩터링 & 풀스택 실무 가이드
📦 실습 예제 풀스택 소스코드 패키지 (.zip)
Spring Boot 3 백엔드 + React 19.3 프론트엔드 + 14단계 챕터별 실습 코드 및 스냅샷이 모두 포함되어 있습니다. (node_modules 및 빌드 캐시 제외)
🗺️ 단일 게시판 코드의 14단계 진화 로드맵
🚀 풀스택 실습 환경 구성 및 따라하기 안내
TIP
jQuery만 써 보셨고 React는 처음이신가요? 1장 코드에는 JSX, useState, useEffect, async/await, interface, axios 같은 낯선 개념이 한꺼번에 등장합니다. 먼저 Chapter 00. 준비운동을 한 번 훑어보고 시작하십시오. 각 장 첫머리의 📋 처음 만나는 개념 표와 본문의 🆕 처음 보는 문법 박스가 새 문법이 어디서 설명되는지 친절하게 짚어 줍니다.
본 교재는 코드를 눈으로 읽기만 하는 책이 아닙니다.
개발자가 직접 한 줄씩 코드를 작성(Hands-on)하고 브라우저와 콘솔, 자동 테스트에서 동작을 검증하며 아키텍처의 진화를 체감할 수 있도록 설계되었습니다.
📥 예제 소스 다운로드 및 Git 저장소
- 압축 파일 직접 다운로드: 📦
react19-board-architecture.zip다운로드
0) 사전 요구사항 및 대상 기술 스택 버전 (Prerequisites)
실습을 시작하기 전 아래 런타임 버전이 설치되어 있는지 확인하십시오. 에디터 확장 ESLint, Prettier와 브라우저 확장 React Developer Tools, Redux DevTools(9장 Zustand 연동용)도 함께 설치하십시오(0장 0.2).
| 구분 | 기술 스택 | 권장 버전 | 비고 |
|---|---|---|---|
| 런타임 | Node.js | v22.x LTS 이상 (최소 v20.19+) | 프론트엔드 빌드 및 Vitest 실행 |
| 백엔드 | Java (JDK) / Spring Boot | JDK 21 LTS / Spring Boot 3.3+ | 내장 H2 인메모리 DB 사용 |
| 코어 | React / TypeScript / Vite | React 19.3 / TS 5.6+ / Vite 5.4+ | useOptimistic, <Activity>, Compiler 대응 |
| 아키텍처 | Zustand / React Router / Axios | Zustand 5.0+ / Router 7.x (또는 6.26+) / Axios 1.7+ | 1분 TTL 캐싱, ProtectedRoute 가드, Single-Flight 인터셉터 |
| 최적화/테스트 | TanStack Virtual / Vitest / RTL / MSW | React Virtual 3.x / Vitest 2.1+ / RTL 16.x / MSW 2.4+ | 10,000건 가상 스크롤, 단위·통합 시나리오 테스트 |
1) 프로젝트 디렉터리 구성
react19-board-architecture/
├── backend/ # Spring Boot 3 백엔드 (H2 DB, REST API: 8080)
│ └── src/main/resources/static/
│ ├── legacy-board.html # 👈 1장에서 해부할 jQuery 레거시 게시판 (부록 D 위젯 실습 겸용)
│ └── docs/ # 👈 이 교재의 HTML 뷰어 (오프라인 열람 가능)
├── frontend/ # React 19.3 + TypeScript 프론트엔드 (Vite: 3000)
│ ├── src/
│ │ ├── App.tsx # 최상위 레이아웃 (내비게이션 + <ErrorBoundary> + <AppRouter>, 11~12장)
│ │ ├── BoardApp.tsx # 👈 메인 컴포넌트. 처음 받으면 14장까지 마친 "최종 완성본"이 들어 있고,
│ │ │ # 1장에서 내용을 비우고 처음부터 직접 작성합니다
│ │ ├── practice/ # 👈 2.5장 미니 React 렌더러, 13장 10,000개 댓글 가상 스크롤 실험 파일
│ │ ├── hooks/ # 👈 5장·13장 로직 분리 Custom Hook (usePagination, usePostFilter, useBoardShortcuts)
│ │ ├── components/ # 👈 6~8장, 10장, 12~13장 컴포넌트 (PostCreateModal, PostDetailModal, LikeButton,
│ │ │ └── common/ # BoardTable<T>, ErrorBoundary, VirtualList 등)
│ │ ├── context/ # 👈 6장 계층형 댓글 트리 Context & Provider (CommentContext.tsx)
│ │ ├── types/ # 👈 7장 DTO 타입 계약 및 런타임 타입 가드 (board.ts, post.ts)
│ │ ├── stores/ # 👈 9~11장 Zustand 스토어 (usePostStore, useDraftStore, useAuthStore)
│ │ ├── router/ # 👈 11장 React Router v7 설정 및 ProtectedRoute 인가 가드
│ │ ├── views/ # 👈 11장 로그인 페이지(LoginPage.tsx) 및 부록 B Ant Design/Tailwind 뷰
│ │ ├── api/ # 👈 12장 Single-Flight httpClient.ts 및 도메인 postRepository.ts
│ │ └── snapshots/ # 👈 장별 BoardApp.tsx 완성본 (막힐 때 비교/복원용)
│ ├── tests/ # 👈 10·12·14장 Vitest + RTL 단위/격리/통합 테스트와 MSW 핸들러(handlers.ts)
│ └── package.json # 프론트엔드 의존성 및 실습/테스트 스크립트
└── .vscode/ # VS Code 공통 설정IMPORTANT
예제 코드는 "최종 완성본"입니다. frontend/src 아래의 스토어, 라우터, API 계층 등은 14장까지 마친 상태로 들어 있어, 받자마자 npm run dev로 완성된 게시판을 볼 수 있습니다. 1장에서는 BoardApp.tsx만 비우고 처음부터 작성하며, 각 장의 본문 코드는 그 장 시점의 모습이라 최종본과 다를 수 있습니다(예: 9~10장 본문 스토어는 axios를 직접 쓰지만, 12장 이후 최종본 스토어는 postRepository를 씁니다). 각 장 첫머리의 🏁 이 장의 시작 파일 박스가 어느 스냅샷에서 시작하는지 알려 주며, 장이 끝나면 snapshots/의 같은 장 파일과 비교하십시오.
2) 터미널 2개로 실습 환경 기동하기
실습을 위해 2개의 터미널 창을 열어 각각 백엔드와 프론트엔드를 실행합니다:
bash
# [터미널 1] 백엔드(Spring Boot 3) 실행 (포트: 8080)
cd backend
./mvnw spring-boot:run
# (Windows PowerShell / CMD의 경우: .\mvnw.cmd spring-boot:run)
# [터미널 2] 프론트엔드(React 19.3) 실행 (포트: 3000)
cd frontend
npm install
npm run dev3) 브라우저 접속 주소
- jQuery 레거시 화면 확인:
http://localhost:8080/legacy-board.html - React 19.3 점진적 리팩터링 실습 화면:
http://localhost:3000 - HTML 교재 뷰어 (웹 서빙):
http://localhost:8080/docs/index.html - 2.5장 미니 React 엔진 터미널 실습:
cd frontend && npm run practice:mini-react - 전체 자동 테스트 실행:
cd frontend && npm run test
🗂 챕터별 원고 바로가기 (Chapters)
TIP
각 장은 일관된 학습 구조로 짜여 있습니다. 📋 처음 만나는 개념 → 🏁 이 장의 시작 파일 → 본문 풀코드 실습(🆕 처음 보는 문법, 일상 비유 & Mermaid 다이어그램, 💡 확인하기, 🔬 심화) → 💪 [직접 해보기] 실습 미션(정답 토글 포함) → 🚀 이번 장 핵심 요약 및 다음 단계(핵심 3줄, 바뀐 파일, 자주 하는 실수, 셀프 체크).
- Chapter 00. 시작하기 전에: jQuery 개발자를 위한 React 19 준비운동 👈 React·JSX·불변성이 처음이라면 여기부터
- Chapter 01. 돌아가기만 하는 사내 레거시: jQuery 게시판의 종말
- Chapter 01.5. React 기본기 실습: 게시판으로 필수 훅과 문법 익히기 👈 React 입문자 필수, 경험자는 건너뛰어도 됨
- Chapter 02. React 렌더링 엔진의 비밀: 가상 DOM(Fiber)과 불변성
- Chapter 02.5. [선택·심화] 50줄로 직접 만드는 미니 React 렌더러 👈 건너뛰어도 3장 이후 실습에 지장 없음
- Chapter 03. 훅의 규칙과 클로저 트랩(Stale Closure)의 정복
- Chapter 04. 한 파일에 몰린 관심사: Fat Component의 위기
- Chapter 04.5. 라우터 맛보기: React Router로 화면을 바꾸고 상태 담기 👈 5장의 URL 검색 필터 전에 꼭 읽기
- Chapter 05. Custom Hook 패턴으로 로직 독립시키기 (+ 첫 자동 테스트)
- Chapter 06. 계층형 댓글 트리와 React Context API (DI 격리)
- Chapter 07. 게시판 DTO와 컴포넌트 경계선의 타입 계약
- Chapter 08. 어디든 재사용 가능한 제네릭
BoardTable<T>제작 - Chapter 09. 상태는 언제 컴포넌트를 떠나야 하는가? (Zustand 철학)
- Chapter 10. '좋아요' 낙관적 업데이트와 React 19.3
useOptimistic& Zustand 롤백 - Chapter 11. 라우터 네비게이션 가드를 활용한 인가(Authorization) AOP
- Chapter 12. HTTP 레이어 격리와 프론트엔드 에러 바운더리(
<ErrorBoundary>) - Chapter 13. 10,000개 댓글 렌더링 최적화와 가상 스크롤 & React 19.3 신기능
- Chapter 14. 실전 Vitest와 Testing Library & MSW 통합 테스트
[부록 (Appendix)] 실무 현장 투입을 위한 엔터프라이즈 확장
- Appendix A. 사내 실무 환경설정 및 Docker/Nginx 배포 가이드
- Appendix B. 사내 표준 UI 라이브러리(Ant Design / shadcn/ui Tailwind) 브릿지 가이드
- Appendix C. 실습 환경·런타임 에러 트러블슈팅 FAQ 12종
- Appendix D. 기존 jQuery 페이지에 React 19 심기: 공존과 점진적 전환 가이드
👥 사내 스터디 리더(진행자)를 위한 5주 운영 키트
퇴근 후 주 2~3회, 회당 1.5~2시간을 기준으로 5주 일정을 권장합니다. 각 장은 끝의 **"실습 미션"**과 **"핵심 요약(셀프 체크)"**으로 마무리하므로, 스터디 첫 10분은 지난주 장들의 셀프 체크를 서로 묻고 답하는 데 쓰면 효과가 배가됩니다.
| 주차 | 범위 | 핵심 성취 | 선택 과제 |
|---|---|---|---|
| Week 1 | 0장, 1장, 1.5장 | jQuery 게시판을 React 19로 옮기고 JSX와 useState·useRef를 손에 익힌다 | 부록 D(기존 jQuery 페이지에 React 위젯 심기) |
| Week 2 | 2장, 3장, 4장, 4.5장 | Fiber 렌더링 원리와 불변성, Stale Closure 해결, 라우터 기초 | 2.5장(미니 React 엔진 직접 만들기) |
| Week 3 | 5장, 6장, 7장 | Custom Hook 분리와 첫 단위 테스트, Context DI, DTO 타입 계약과 타입 가드 | 7장 실습 미션(isPostDraft) |
| Week 4 | 8장, 9장, 10장 | 제네릭 BoardTable<T>, Zustand 1분 캐시, useOptimistic + 롤백 테스트 | 8장 사원 목록 테이블 미션 |
| Week 5 | 11장, 12장, 13장, 14장 | <ProtectedRoute> 가드, Single-Flight 인터셉터, @tanstack/react-virtual, RTL 통합 테스트 | 부록 A·B 배포 및 UI 브릿지 |
[Week 1] Ch 00 ~ 01.5: 선언적 멘탈 모델과 JSX
- 토론 질문: "jQuery에서
$('#tbody').html()로 DOM을 직접 갈아 끼울 때와, React에서posts상태를 바꾸고 컴포넌트 함수를 다시 실행할 때의 렌더링 멘탈 모델 차이는 무엇인가?" - PR 검수 포인트: 컴포넌트 내부에서
document.querySelector나innerHTML을 직접 호출하지 않고, 오직 JSX와useState로만 화면을 선언적으로 그리는가? 리스트 렌더링의key에 배열 인덱스 대신 고유 id(post.id)를 쓰는가?
[Week 2] Ch 02 ~ 04.5: 불변성의 원리와 클로저 트랩, 그리고 라우터
- 토론 질문: "
post.title = '새제목'처럼 기존 객체 내부를 직접 고치면 왜 React 화면이 갱신되지 않는가?Object.is참조 비교와 불변성이 React 렌더링에 미치는 영향은?" - PR 검수 포인트: 상태를 변경할 때 항상
[...prev, newItem]이나{ ...prev, title }처럼 새로운 불변 객체/배열을 만드는가?useEffect의 의존성 배열에 쓰인 외부 변수가 누락 없이 들어갔는가?
[Week 3] Ch 05 ~ 07: Custom Hook, Context, 타입 계약
- 토론 질문: "컴포넌트를 작게 쪼개는 UI 분할과 Custom Hook으로 로직을 도려내는 것은 언제 각각 쓰는가? 모든 데이터를 props로 내려보내지 않고 Context API를 써야 하는 명확한 기준은?"
- PR 검수 포인트:
usePagination,usePostFilter가 컴포넌트 뷰와 완전히 독립되어 있는가? 백엔드 Spring DTO와 프론트엔드types/board.ts가any없이 1:1로 일치하며 모달 Props 계약이 엄격한가?
[Week 4] Ch 08 ~ 10: 제네릭 컴포넌트와 Zustand, 낙관적 업데이트
- 토론 질문: "모든 상태를 Zustand 전역 스토어에 넣으면 왜 안 되는가? 컴포넌트 로컬 상태, URL 파라미터, Zustand 전역 상태의 분리 기준은 무엇인가?"
- PR 검수 포인트: 제네릭
BoardTable<T>의 컬럼 키 오타가 컴파일 시점에 빨간 줄로 잡히는가? Zustand 구독 시useShallow나 단일 선택자를 썼는가?useOptimistic과 스토어 롤백 테스트가 통과하는가?
[Week 5] Ch 11 ~ 14: 라우터 인가, HTTP 격리, 가상화 최적화, 통합 테스트
- 토론 질문: "프론트엔드 화면 컴포넌트에서
axios.get을 직접 부르는 것을 왜 코드 리뷰에서 엄격히 금지해야 하는가? 클라이언트<ProtectedRoute>가드만으로 보안이 완성되지 않는 이유는?" - PR 검수 포인트:
postRepository와 Single-FlighthttpClient로 네트워크 계층이 격리되었는가? 10,000개 댓글 렌더링 시@tanstack/react-virtual로 60fps가 유지되는가?npm run test로 MSW 기반 통합 테스트 3종이 모두 통과하는가?