diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..22d8c2bb --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,57 @@ +name: Deploy to GitHub Pages + +on: + push: + branches: + - main + + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: latest + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm run build + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: packages/app/dist + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/README.md b/README.md index 5d667921..097061c1 100644 --- a/README.md +++ b/README.md @@ -1,136 +1,256 @@ -# React 구현 과제 문서 - -React의 핵심 기능을 직접 구현해보며 내부 동작 원리를 이해하기 위한 종합 가이드입니다. - -## 📚 문서 구성 - -### [01. 구현 가이드](docs/01-implementation-guide.md) -- **함수 인터페이스**: 각 모듈별 타입 시그니처와 책임 -- **수도코드**: 렌더링, 훅, 비교 로직의 전체 흐름 -- **단계별 로드맵**: 기본·심화 과제에 맞춘 구현 체크포인트 - -### [02. 시퀀스 다이어그램](docs/02-sequence-diagrams.md) -- **기본 플로우**: 루트 초기화, 렌더, 훅 실행, Reconciliation -- **심화 플로우**: 고급 훅(useMemo/useRef/useAutoCallback)과 HOC 처리 -- **시각 자료**: 주요 함수 호출 순서와 데이터 이동을 다이어그램으로 정리 - -### [03. 기초 지식](docs/03-fundamental-knowledge.md) -- **VNode & 경로 모델**: JSX 정규화와 key/경로 규칙 -- **렌더 사이클**: 컨텍스트 초기화, 렌더 예약, 훅 정리 절차 -- **리컨실리에이션 전략**: 자식 비교, anchor 계산, Fragment 다루기 -- **DOM 상호작용**: 속성·스타일·이벤트 업데이트 패턴 -- **Hook 컨텍스트**: 상태 저장 구조와 useState/useEffect 규칙 -- **스케줄링 & 유틸**: 마이크로태스크 큐, equality 함수, memo 패턴 - -## 🎯 학습 목표 - -이 과제를 통해 다음을 이해할 수 있습니다: - -- **Virtual DOM**의 동작 원리와 Reconciliation 알고리즘 -- **React Hooks**의 내부 구현과 상태 관리 메커니즘 -- **컴포넌트 생명주기**와 렌더링 최적화 기법 -- **메모이제이션**과 **HOC** 패턴의 구현 원리 -- **JavaScript 기반 DOM 조작**과 이벤트 처리 전략 - -## 🚀 시작하기 - -1. **기초 지식 학습**: [03-fundamental-knowledge.md](docs/03-fundamental-knowledge.md)로 필수 개념 정리 -2. **시퀀스 이해**: [02-sequence-diagrams.md](docs/02-sequence-diagrams.md)에서 전체 호출 흐름 파악 -3. **단계별 구현**: [01-implementation-guide.md](docs/01-implementation-guide.md)의 체크리스트에 따라 진행 - -## 📋 구현 체크리스트 - -### ✅ 기본 과제 -- [ ] **Phase 1 · VNode와 기초 유틸리티** (`core/constants.ts`, `core/elements.ts`, `utils/equals.ts`, `utils/validators.ts`) - - `TEXT_ELEMENT`, `Fragment` 등의 심볼 정의 - - `isEmptyValue`, `shallowEquals`, `deepEquals` 등 공용 유틸 구현 - - `createElement`, `normalizeNode`, `createChildPath`로 JSX → VNode 정규화 -- [ ] **Phase 2 · 컨텍스트와 루트 초기화** (`core/context.ts`, `core/types.ts`, `core/setup.ts`, `client/index.ts`) - - 루트/훅 컨텍스트 구조 정의 및 초기화 - - `setup`으로 루트 렌더 흐름 구축, `createRoot` 노출 -- [ ] **Phase 3 · DOM 인터페이스** (`core/dom.ts`) - - 속성/스타일/이벤트 업데이트 규칙 구현 - - DOM 노드 탐색·삽입·제거 유틸 완성 -- [ ] **Phase 4 · 렌더 스케줄링** (`utils/enqueue.ts`, `core/render.ts`) - - 마이크로태스크 기반 스케줄러(`withEnqueue`) 작성 - - `render`/`enqueueRender`로 루트 렌더 사이클 구성 -- [ ] **Phase 5 · Reconciliation** (`core/reconciler.ts`) - - 노드 타입별 마운트/업데이트/언마운트 로직 구현 - - 자식 비교, key 매칭, anchor 계산으로 DOM 이동 최소화 -- [ ] **Phase 6 · 기본 Hook 시스템** (`core/hooks.ts`) - - 훅 커서·경로 추적과 상태 저장 구조 완성 - - `useState`, `useEffect`, 이펙트 큐/cleanup, 미사용 훅 정리 +## 과제 체크포인트 + +### 배포 링크 + +[배포링크](https://parksubeom.github.io/front_7th_chapter2-2/) + + +### 기본과제 + +#### Phase 1: VNode와 기초 유틸리티 +- [x] `core/elements.ts`: `createElement`, `normalizeNode`, `createChildPath` +- [x] `utils/validators.ts`: `isEmptyValue` +- [x] `utils/equals.ts`: `shallowEquals`, `deepEquals` + +#### Phase 2: 컨텍스트와 루트 초기화 +- [x] `core/types.ts`: VNode/Instance/Context 타입 선언 +- [x] `core/context.ts`: 루트/훅 컨텍스트와 경로 스택 관리 +- [x] `core/setup.ts`: 컨테이너 초기화, 컨텍스트 리셋, 루트 렌더 트리거 + +#### Phase 3: DOM 인터페이스 구축 +- [x] `core/dom.ts`: 속성/스타일/이벤트 적용 규칙, DOM 노드 탐색/삽입/제거 + +#### Phase 4: 렌더 스케줄링 +- [x] `utils/enqueue.ts`: `enqueue`, `withEnqueue`로 마이크로태스크 큐 구성 +- [x] `core/render.ts`: `render`, `enqueueRender`로 루트 렌더 사이클 구현 + +#### Phase 5: Reconciliation +- [x] `core/reconciler.ts`: 마운트/업데이트/언마운트, 자식 비교, key/anchor 처리 +- [x] `core/dom.ts`: Reconciliation에서 사용할 DOM 재배치 보조 함수 확인 + +#### Phase 6: 기본 Hook 시스템 +- [x] `core/hooks.ts`: 훅 상태 저장, `useState`, `useEffect`, cleanup/queue 관리 +- [x] `core/context.ts`: 훅 커서 증가, 방문 경로 기록, 미사용 훅 정리 **기본 과제 완료 기준**: `basic.equals.test.tsx`, `basic.mini-react.test.tsx` 전부 통과 -### 🚀 심화 과제 -- [ ] **Phase 7 · 확장 Hook & HOC** (`hooks/*.ts`, `hocs/*.ts`) - - `useRef`, `useMemo`, `useCallback`, `useDeepMemo`, `useAutoCallback` - - `memo`, `deepMemo` 고차 컴포넌트로 렌더 최적화 +### 심화과제 + +#### Phase 7: 확장 Hook & HOC +- [x] `hooks/useRef.ts`: ref 객체 유지 +- [x] `hooks/useMemo.ts`, `hooks/useCallback.ts`: shallow 비교 기반 메모이제이션 +- [x] `hooks/useDeepMemo.ts`, `hooks/useAutoCallback.ts`: deep 비교/자동 콜백 헬퍼 +- [x] `hocs/memo.ts`, `hocs/deepMemo.ts`: props 비교 기반 컴포넌트 메모이제이션 + +## 과제 셀프회고 + + + +### 트러블슈팅 및 해결 + +
+Phase 1: VNode와 기초 유틸리티 + +1. **배열 렌더링 테스트 실패** + - **원인:** JSX에서 `{index}`처럼 숫자를 넣으면 그대로 `number` 타입이 `nodeValue`에 전달됐습니다. 그런데 테스트는 문자열을 기대하고 있는 상태였습니다. + - **해결:** `createTextElement`에서 `String(nodeValue)`로 강제 변환하도록 수정했습니다. 덕분에 숫자도 문제없이 화면에 표시됩니다. + +2. **함수형 컴포넌트 테스트 실패** + - **원인:** 자식이 없는 컴포넌트(``)임에도 `props.children`이 빈 배열로 설정되면서 테스트가 꼬였습니다. + - **해결:** `createElement`에 분기 처리를 넣어, **DOM/Fragment 타입이거나 실제 자식이 있을 때만** `props.children`을 세팅하도록 변경했습니다. + +
+ +
+Phase 3: DOM 인터페이스 구축 + +1. **style 객체 반영 실패** + - **원인:** 임시 mount 함수는 `className`만 적용하고 `style`은 무시했습니다. + - 그래서 `div.style.backgroundColor`가 항상 `''`가 되면서 테스트가 실패했습니다. + - **해결:** `core/dom.ts`에 `setDomProps`와 `updateDomProps`를 구현했습니다. + - props 순회를 통해 `style`, 이벤트, boolean 속성, `data-` 속성 등을 올바른 DOM API로 적용하도록 했습니다. + - 작은 로직이지만, DOM과 props 사이 연결의 중요성을 몸소 느꼈습니다. + +2. **setup.ts에서 mount 연결** + - **문제:** dom.ts는 구현했는데, setup.ts에서 연결하지 않아 여전히 스타일이 적용되지 않았습니다. + - **해결:** mount 함수에서 className 하드코딩을 제거하고, `setDomProps(dom, node.props)`를 호출하도록 수정했습니다. + - 이제 모든 props가 DOM에 정상 반영됩니다. + +
+ +
+Phase 3: <select> 기본값이 URL/스토어와 다르게 표시된 이슈 + +1. **기본값 불일치 문제 발생** + - **원인:** + 브라우저는 `