-
Notifications
You must be signed in to change notification settings - Fork 49
[4팀 안소은] Chapter 2-2. 나만의 React 만들기 #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- createElement: JSX -> VNode 변환 (Fragment 지원) - nomalizeNode: 다양한 타입 정규화 - createChildPath: 컴포넌트 고유 경로 생성 - isEmptyValue: 렌더링 불필요 값 필터링
- context: root/hooks 상태 관리 및 getter 구현 - enqueue: 마이크로태스크 기반 비동기 실행 - withEnqueue: 중복 방지 스케줄러
- DOM 탐색 : getDomNodes, getFirstDom - DOM 조작 : insertInstance, removeInstance - 속성 관리 : setDomProps, updateDomProps - 이벤트, style, className 처리
- setup: 초기 설정 및 컨텍스트 초기화 - render: 루트 렌더링 및 훅 정리 - reconcile: mount/update/unmount 처리 - reconcileChildren: 자식 배열 재조정
- useState: 상태 관리 및 리렌더링 트리거 - useEffect: deps 비교 및 비동기 실행 - cleanupUnusedHooks: 미사용 훅 정리 - flushEffects: effect 실행 트리거 - fix(dom.ts): input에 value속성 처리 개선
문제: - 컴포넌트가 다른 컴포넌트를 반환할 때 같은 path 사용 - 부모 컴포넌트의 hooks와 자식 컴포넌트의 hooks가 충돌 - memo HOC 등에서 useRef와 useState가 같은 인덱스 사용 해결: - 자식 노드가 컴포넌트면 createChildPath로 새 path 생성 - 자식 노드가 DOM이면 기존 path 유지 - mount와 update 모두 동일하게 처리
[Joshua] 4팀 코드 리뷰역시 썸머언니🤔 코드 슬쩍 보는데도 군더더기 없이 깔끔하네요 |
|
언니 배포링크 빠졌어요 https://ahnsummer.github.io/front_7th_chapter2-2/ |
|
아래는 Senior React / Frontend Architecture 관점에서의 정석적인 답변이야. 🔥 결론 먼저:**“학습용 / 단일 루트 / CSR 전용이면 전역 context는 충분.여러 루트, SSR, concurrent 렌더링이 보이면 → 반드시 context 인스턴스화를 고려해야 한다.”** React도 결국 root 단위로 독립된 Fiber tree + Hook state container를 생성한다. 1. Context 중앙화의 Trade-off 분석 (네가 잘 정리해놨고, 조금 더 확장해줄게)✔ 이전 방식: 노드 객체가 상태를 직접 가짐
💡 학습용 구현에서는 오히려 직관적이지만, 확장성은 가장 낮은 방식. ✔ 현재 방식: 중앙 Context(Map) 기반 전역 상태 컨테이너
💡 즉, "싱글 루트 + 싱글 스레드 렌더링"이라는 전제에서만 안정적이다. 2. 핵심 질문:🔍 여러 루트를 동시에 렌더링하거나 SSR을 고려하면?→ 전역 context는 바로 한계에 부딪힌다.React가 root마다 별도 FiberRoot + Hook state container를 만들어온 이유. 왜냐면… ❗ 문제 1) 훅 커서/상태 충돌두 개의 다른 트리가 동시에 render() 한다면: 이 코드가 서로의 path를 오염시킨다. ❗ 문제 2) effect queue 충돌전역 ❗ 문제 3) SSR은 “요청마다 루트가 하나씩” 필요전역 context를 쓰면 동시 요청 처리 불가능 → Memory leak & state contamination 실제 React도 SSR에서 per-request root container를 생성한다. 3. 실무 기준: React는 왜 전역 context를 쓰지 않는가?React의 구조는 다음과 같다: 즉, **"root 단위로 완전히 분리된 상태 저장소"**가 있다. 그래서:
4. 결론적으로:🔥 “Context를 함수로 만들어 인스턴스화”가 맞다.즉, 이런 형태: export const createRenderContext = () => ({
state: new Map(),
cursor: new Map(),
visited: new Set(),
componentStack: [],
effects: { queue: [] },
container: null,
node: null,
instance: null,
});그리고 render 단계에서: const ctx = createRenderContext();
renderElement(rootVNode, rootContainer, ctx);📌 장점
📌 이 방식은 "React의 Fiber Root Container"와 동일한 철학. 5. 하지만… 정말 실무에서도 무조건 필요한가?✔ 단일 루트 + CSR 전용 웹앱전역 context 충분히 실무에서도 문제 없음 ✔ 하지만 아래 조건 중 하나라도 걸리면 반드시 인스턴스화해야 함
6. Senior React 관점의 조언📌 “지금 단계에서 전역 context는 아주 합리적 선택이다.” 너의 목표가
이거라면 전역 하나만 두는 게 구조 파악이 가장 직관적이고, 실습도 빠르다. 📌 하지만 설계가 어느 정도 안정화되면 반드시 root container로 context를 분리해라. 대신 다음과 같이 “context 인스턴스 전략”을 추천: ✔ 최소 단위: RootContext = 훅/인스턴스 상태 컨테이너✔ 글로벌 단위: 환경 설정(옵션), 스케줄러(작업 큐) 정도만 전역 유지이게 지금 React의 architecture와 가장 가깝다. 🔥 최종 한 줄 요약전역 context는 “단일 루트 CSR 학습용”으로는 완벽한 선택. 필요하면
|
과제 체크포인트
배포 링크
https://ahnsummer.github.io/front_7th_chapter2-2/
기본과제
Phase 1: VNode와 기초 유틸리티
core/elements.ts:createElement,normalizeNode,createChildPathutils/validators.ts:isEmptyValueutils/equals.ts:shallowEquals,deepEqualsPhase 2: 컨텍스트와 루트 초기화
core/types.ts: VNode/Instance/Context 타입 선언core/context.ts: 루트/훅 컨텍스트와 경로 스택 관리core/setup.ts: 컨테이너 초기화, 컨텍스트 리셋, 루트 렌더 트리거Phase 3: DOM 인터페이스 구축
core/dom.ts: 속성/스타일/이벤트 적용 규칙, DOM 노드 탐색/삽입/제거Phase 4: 렌더 스케줄링
utils/enqueue.ts:enqueue,withEnqueue로 마이크로태스크 큐 구성core/render.ts:render,enqueueRender로 루트 렌더 사이클 구현Phase 5: Reconciliation
core/reconciler.ts: 마운트/업데이트/언마운트, 자식 비교, key/anchor 처리core/dom.ts: Reconciliation에서 사용할 DOM 재배치 보조 함수 확인Phase 6: 기본 Hook 시스템
core/hooks.ts: 훅 상태 저장,useState,useEffect, cleanup/queue 관리core/context.ts: 훅 커서 증가, 방문 경로 기록, 미사용 훅 정리기본 과제 완료 기준:
basic.equals.test.tsx,basic.mini-react.test.tsx전부 통과심화과제
Phase 7: 확장 Hook & HOC
hooks/useRef.ts: ref 객체 유지hooks/useMemo.ts,hooks/useCallback.ts: shallow 비교 기반 메모이제이션hooks/useDeepMemo.ts,hooks/useAutoCallback.ts: deep 비교/자동 콜백 헬퍼hocs/memo.ts,hocs/deepMemo.ts: props 비교 기반 컴포넌트 메모이제이션과제 셀프회고
아하! 모먼트 (A-ha! Moment)
1. 구조 설계의 중요성
이전 구현 (2-1): 200줄짜리 render 함수 하나에 모든 로직이 섞여있었습니다. DOM 생성, 컴포넌트 실행, 상태 관리, 자식 렌더링이 한 곳에 있어서 어디서 문제가 생기는지 파악하기 어려웠습니다.
이번 구현: reconcile, mount, update, reconcileChildren 등으로 역할을 명확히 분리하니, 디버깅할 때 "아, 이건 reconcile의 update 부분 문제겠다"라고 바로 파악할 수 있었습니다. **"좋은 구조는 코드를 읽지 않아도 이해하게 만든다"**는 것을 체감했습니다.
2. 용어의 힘
처음 구현할 때는 "이전 것과 새것을 비교해서 DOM을 업데이트하는 함수"라고만 생각했는데, 이것이 Reconciliation이라는 명확한 용어가 있다는 것을 알고 나니, React 공식 문서나 다른 자료를 찾아볼 때도 훨씬 수월했습니다. 용어를 아는 것이 학습의 속도를 올려준다는 것을 깨달았습니다.
3. Map이 searchCurrentNode보다 훨씬 효율적
searchCurrentNode(key)로 전체 트리를 탐색해서 노드를 찾음 → O(n)context.hooks.state.get(path)→ O(1)Map을 활용한 직접 접근이 얼마나 효율적인지, 그리고 자료구조 선택이 성능에 미치는 영향을 체감했습니다.
기술적 성장
이번 과제를 통해 좀 더 깊게 학습한 개념
VNode와 Instance의 명확한 분리
Reconciliation의 4가지 시나리오
Context 기반 중앙화된 상태 관리
Map<path, hooks[]>구조로 중앙 관리마이크로태스크 스케줄링과 배치 처리
withEnqueue로 여러 setState를 한 번의 render로 배치 처리클로저의 실전 적용
withEnqueue의scheduled플래그, useState의hooks[cursor]참조 등 실제 패턴을 직접 구현하며 클로저가 상태 관리의 핵심임을 깨달음구현 과정에서 마주친 기술적 도전
"The node to be removed is not a child" 에러
중첩 컴포넌트 hooks 충돌
createChildPath로 고유 path 생성cursor 초기화 타이밍
cursor.set(path, 0)을 명시적으로 하니 오히려 충돌currentCursorgetter가 이미 처리하는데 중복코드 품질
리팩토링이 필요한 부분
DOM 속성 처리 중복
applyEventHandler,applyStyle등)에러 경계 부족
코드 설계 관련 고민과 결정
"책임 분리" vs "성능 최적화"
"명시적 초기화" vs "Getter 신뢰"
학습 효과 분석
가장 큰 배움
"아키텍처의 중요성"
이전 구현(coreV2)에서는 200줄짜리 render 함수를 디버깅하느라 고생했는데, 이번엔 처음부터 구조가 명확히 정의되어 있어서 각 Phase를 하나씩 완성해나가는 느낌이었습니다.
비교:
파일 구조만 봐도 차이가 명확합니다:
Reconciliation 알고리즘
단 4가지 규칙(unmount/mount/replace/update)으로 모든 렌더링 케이스를 처리한다는 것이 놀라웠습니다. 복잡해 보이는 React도 결국 명확한 원칙의 조합이라는 것을 이해했습니다.
중앙관리식 Hooks의 장점
이전엔 각 노드에 state 배열을 저장했는데, 이번엔
Map<path, hooks[]>구조로 중앙 관리하니:배열과 인덱스라는 단순한 아이디어가, Map과 path와 cursor가 결합되어 강력한 시스템이 된다는 것을 깨달았습니다.
추가 학습이 필요한 영역
과제 피드백
과제에서 좋았던 부분
테스트 주도 학습
명확한 구조 제시
과제에서 어려웠던 부분
reconcileChildren 구현의 복잡도
디버깅 도구 부족
리뷰 받고 싶은 내용
1. Context 중앙화의 trade-off
이전 방식: 각 노드 객체에 상태 분산 저장
이번 방식: Context의 Map으로 중앙 관리
여러 루트를 동시에 렌더링하거나 SSR을 지원하려면 Context를 함수로 생성하여 인스턴스화하는 것이 나을까요? 아니면 현재 전역 context 구조가 실무에서도 충분한 수준인가요?
4팀 코드 리뷰