[2팀 정도은] Chapter 1-2. 프레임워크 없이 SPA 만들기 (2)#43
Open
nemobim wants to merge 15 commits into
Open
Conversation
- children 배열을 평탄화하는 flattenArray 작업 추가
- createElement에서 속성/이벤트 처리를 updateAttributes로 위임하고 배열/자식 처리 개선 - eventManager에서 위임된 이벤트 리스너와 루트 요소 추적 관리 개선 - normalizeVNode에서 자식 요소 정규화 및 함수형 컴포넌트 재귀 처리 단순화 - renderElement에서 초기 렌더링과 업데이트 구분 개선 - updateElement에서 속성 및 자식 요소에 대한 더 강력한 diff 알고리즘 적용
|
소문듣고왔습니다 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
과제 체크포인트
배포 링크
https://nemobim.github.io/front_6th_chapter1-2/
기본과제
가상돔을 기반으로 렌더링하기
이벤트 위임
심화 과제
Diff 알고리즘 구현
과제 셀프회고
기술적 성장
중첩 배열과 JSX 트랜스파일 이해
위와 같은 JSX 구조는 트랜스파일 과정을 거치며 다음과 같이 변환될 수 있습니다:
이 과정에서 중첩 배열이 생기는 이유에 대해 궁금했는데, 아래와 같은 경우들로 인해 발생할 수 있음을 이해하게 되었습니다.
왜 중첩 배열이 발생하는가?
condition && <Component />패턴은false를 반환할 수 있고, 결과적으로 배열 내에 다양한 값이 혼재함return [<A />, <B />]형태로 배열을 직접 반환함WeakMap이란 무엇인가
WeakMap은 자바스크립트 내장 객체 중 하나로 key로 "객체만" 가질 수 있는 Map으로 이름처럼 "약하게 연결(weakly held)"되어있다.코어 시스템 이해
1. createVNode.js - Virtual Node 생성
React의
createElement와 유사한 Virtual Node 생성 함수type,props,children을 가진 VNode 객체 생성2. createElement.js - DOM 요소 생성
VNode를 실제 DOM 요소로 변환하는 핵심 함수
주요 처리 로직:
DocumentFragment생성속성 처리:
className→class어트리뷰트onClick등)checked,disabled등)style객체 처리3. normalizeVNode.js - VNode 정규화
다양한 타입의 노드를 일관된 형태로 정규화
4. renderElement.js - 렌더링 엔진
VNode를 실제 DOM에 렌더링하는 메인 함수
innerHTML = '')updateElement를 통한 diff 기반 효율적 업데이트5. updateElement.js - DOM 업데이트
Virtual DOM의 핵심인 diff 알고리즘 구현
<div>→<span>)6. eventManager.js - 이벤트 위임 시스템
효율적인 이벤트 관리를 위한 이벤트 위임 구현
주요 함수
setupEventListeners: 루트에 이벤트 리스너 등록addEvent: 요소에 이벤트 핸들러 등록removeEvent: 이벤트 핸들러 제거전체 동작 흐름
graph TD A[JSX/함수 호출] --> B[createVNode] B --> C[normalizeVNode] C --> D[renderElement] D --> E{최초 렌더링?} E -->|Yes| F[createElement] E -->|No| G[updateElement] F --> H[setupEventListeners] G --> I[DOM 업데이트 완료] H --> I코드 품질
처음 렌더링된 VNode는 container의 _vNode 속성에 저장해두고 이후 화면이 다시 렌더링될 경우 이전 VNode와 새 VNode를 비교해 필요한 부분만 변경하도록 updateElement를 호출하는 방식으로 구현했습니다. 매번 전체를 다시 그리는 게 아니라 변경된 부분만 DOM에 반영하도록 하고 이때 이벤트는 초기에 한 번만 등록되도록 처리했습니다.
처음에는 사용할 이벤트 타입들을 코드에 직접 하드코딩했는데, 이렇게 하면 새로운 이벤트가 생길 때마다 일일이 코드를 수정해줘야 할거 같아서 이벤트 타입을 동적으로 관리할 수 있도록 delegatedEvents라는 Set을 만들었습니다. 새로운 이벤트 타입이 등장하면 해당 타입을 Set에 등록하고, 루트 요소에 한 번만 리스너를 붙이도록 구조를 변경했습니다.
학습 효과 분석
eventManager 관련
Map을 사용하여 같은 이벤트 타입이 여러 번 등록되는 것을 방지할 수 있었다.
버블링을 활용한 이벤트 탐색
실제 클릭된 요소부터 컨테이너까지 DOM 트리를 역순으로 탐색하며 등록된 핸들러를 찾아 실행해준다.
이 방법을 사용하면 수천 개의 요소에 개별 리스너를 다는 대신, 하나의 부모에서 모든 이벤트를 처리할 수 있다.
과제 피드백
리뷰 받고 싶은 내용
처음에는 flat(Infinity)를 사용했지만, 배열의 깊이가 2차원으로 고정되어 있는 것 같아 재귀 함수로 다시 구현했습니다. 이처럼 배열의 뎁스를 명확히 알고 있을 경우, flat() 대신 직접 구현하는 방식이 성능면에서 더 좋을까요... 차이가 미미하다면 가독성을 우선하는 게 더 나을 것 같은데 일반적으로 어느 정도를 "미미하다"고 보는지도 궁금합니다.
처음에는
normalizeVNode를 아래와 같이 작성했습니다:이 코드는 단위 테스트에서는 통과했지만, e2e 테스트에서 실패해서 다음과 같이
filter(Boolean)을 추가해 수정했습니다:앞단에서도
filter(Boolean)처리를 해주는 부분이 많았고 이 시점에서 추가로 필터링하지 않아도 된다고 생각했는데 이 코드를 추가하자 테스트가 통과했습니다. 왜 이 필터링이 필요한 건지, 어떤 값이false처리되어 걸러지는지 정확히 이해하지 못하겠습니다… 혹시 어떤 케이스 때문에 이런 처리가 꼭 필요한 걸까요?