esoby 님의 상세페이지[4팀 김소희] Chapter 1-2. 프레임워크 없이 SPA 만들기 (2)

과제 체크포인트

배포 링크

esoby.github.io/front_6th_chapter1-2/

기본과제

가상돔을 기반으로 렌더링하기

  • createVNode 함수를 이용하여 vNode를 만든다.
  • normalizeVNode 함수를 이용하여 vNode를 정규화한다.
  • createElement 함수를 이용하여 vNode를 실제 DOM으로 만든다.
  • 결과적으로, JSX를 실제 DOM으로 변환할 수 있도록 만들었다.

이벤트 위임

  • 노드를 생성할 때 이벤트를 직접 등록하는게 아니라 이벤트 위임 방식으로 등록해야 한다
  • 동적으로 추가된 요소에도 이벤트가 정상적으로 작동해야 한다
  • 이벤트 핸들러가 제거되면 더 이상 호출되지 않아야 한다

심화 과제

Diff 알고리즘 구현

  • 초기 렌더링이 올바르게 수행되어야 한다
  • diff 알고리즘을 통해 변경된 부분만 업데이트해야 한다
  • 새로운 요소를 추가하고 불필요한 요소를 제거해야 한다
  • 요소의 속성만 변경되었을 때 요소를 재사용해야 한다
  • 요소의 타입이 변경되었을 때 새로운 요소를 생성해야 한다

과제 셀프회고

기술적 성장

  • 가상 DOM을 활용해 실제 DOM을 업데이트하는 흐름을 어설프게나마 구현해보니 이론으로만 외웠던 이전보다 더 뚜렷하게 가상 DOM의 핵심 원리를 이해할 수 있었습니다. 특히 뭔가 아주 고도의 내용일 것만 같던 diff 알고리즘을 코드 구현해보았다는 게 성취감이 컸던 거 같습니다.
  • 오랜만에 재귀 함수를 만나서 그런지 낯을 좀 가렸는데 다시 꽤나 친해진 것 같습니다.
  • 예상 외로 구현보다는 돔의 property와 attribute의 상호작용을 이해하는 데에 많은 시간이 든 것 같습니다. 척척 동기화가 되지 않는다는 사실을 알기까지도 시간이 많이 걸렸습니다. 두 개념을 모호하게 알고 있어서 테스트 실패가 거의 두 요소의 동기화를 빠뜨린 데에서 났던 것 같습니다 ㅠ

코드 품질

  • 이벤트 매니저에서 리스너 재설정 시 위임 이벤트 중복 리스너 등록을 방지하는 로직이 가장 마음에 드는 것 같습니다! 아이디어는 지피티가 줬지만 ...,,
  • element를 만들 때 updateAttributes를 거치는데 create와 update 시 사용하는 함수가 분리되어 있는 점이 아쉽습니다. 테스트 통과를 목표로 일단 보류했지만 시간적 여유가 더 있었다면 중복 코드 제거하고 하나의 함수로 리팩토링했을 것 같습니다!

학습 효과 분석

  • 포기하지 말자 ,,,는 마인드 획득
  • 실무에서 라이브러리나 프레임워크 의존도가 높았는데 이번 경험으로 바닐라 js 구현에 대한 망설임이 줄었숩니다!
  • 최적화된 고오급 diffing 알고리즘에 대해 더 공부해보고 싶고, 실제 프레임워크 구현 내용도 뜯어보고 싶다는 생각이 듭니다!

과제 피드백

  • boolean 속성 처리하는 부분 가이드라인이 애매하게 느껴져서 테스트 코드를 뜯어보면서 조건을 추가했는데 그 과정에서 삽질을 많이 한 것 같습니다 ㅠ.ㅠ
  • 첫번째 과제에서 이벤트를 등록할 때 이벤트 위임 방식을 적용해보고자 최대한 부모의 컨테이너에 리스너를 붙여보면서 이런저런 의문이 들었었는데 event manager 구현으로 싹 해소 됐습니다. 공부가 정말 많이 된 것 같아요!

리뷰 받고 싶은 내용

  • 코드 작성 스타일에 대해 ,, 혹시나 어떤 습관이 발견되었다면 알려주세요!
  • 지금까지 구현된 내용에서 리액트와 같은 프레임워크 구현으로 이어간다면 이 다음 스텝은 어떤 게 되어야 하는지 궁금합니다!

감사합니당 ☺️

과제 피드백

안녕하세요 소희~ 수고 많았어요~ 이번 과제는 React의 핵심 원리인 가상 DOM과 diff 알고리즘을 직접 구현해보면서, 프레임워크가 어떻게 효율적인 렌더링을 수행하는지 이해하는 것이 목표였습니다. 무엇보다 "필요가 진정한 공부를 만든다"는 경험을 했기를 바래요. 단순히 이론으로 아는 것과 실제로 구현하기 위해 필요한 지식을 찾아가며 학습하는 것은 완전히 다른 깊이의 이해를 가져다준다는 것을 느꼈기를 바래요. 이러한 코드들이 당장 실무에서는 쓰이지 않겠지만 개발을 더 선명하게 이해해주는 사고방식을 만드는데 도움을 준답니다.

코드를 살펴보니 특히 이벤트 위임 시스템을 3-depth Map 구조(Map<Element, Map<EventType, Set<Handler>>>)로 체계적으로 구현하신 점이 인상적입니다. 중복 리스너 등록 방지를 위해 attachedListeners를 별도로 관리하고, 활성 이벤트 타입만 동적으로 등록하는 최적화도 잘 적용하셨어요.

회고에서 언급하신 DOM의 property와 attribute 차이점을 파악하는 데 어려움을 겪으셨다는 부분도 공감됩니다. 실제로 checked, disabled 같은 boolean 속성들은 attribute와 property가 완벽히 동기화되지 않아 많은 개발자들이 혼란을 겪는 부분입니다. 이를 정확히 구분해서 처리하신 것은 깊이 있는 학습의 결과라고 생각합니다.

코드 상에서 몇 가지 개선할 수 있는 부분을 짚어보자면

  1. WeakMap을 사용해보세요. DOM 요소들은 화면에서 사용되지 않으면 메모리에서 해제되도록 되어 있는데 Map의 key에 보관이 되면 메모리 누수가 발생하게 됩니다. 이를 방지하지 위한 도구가 WeakMap인데요 DOM과 같이 브라우저 API의 값을 key로 써야 하는 상황이라면 WeakMap을 사용하는게 좋습니다.

  2. updateAttributes 중복 제거: 회고에서도 언급하셨듯이 createElement와 updateElement에서 속성 처리 로직이 중복되어 있습니다. 공통 유틸리티 함수로 추출하면 유지보수가 더 쉬워지겠죠. 뭔가 해야겠다 생각하면 한번 시도해보는 것도 좋아요!

  3. 이벤트 버블링 최적화: 현재 while문으로 부모를 순회하며 핸들러를 찾는데, 최근에는 event.composedPath() 라는 API도 나와서 최신 Native API들도 한번 찾아보는 것도 좋습니다.


Q) 코드 작성 스타일에 대한 습관 => 전반적으로 깔끔하고 읽기 쉬운 코드를 작성하셨습니다. 특히 주석으로 자료구조를 명시한 점(// el -> event type -> handlers)이 좋았습니다. 다만 복잡한 조건문에서는 early return 패턴을 더 활용하면 가독성이 향상될 것 같습니다.

Q) 다음 스텝은 무엇인가요? => 반복적인 컨텐츠를 key를 통한 최적화 기법, 컴포넌트의 핵심인 useState와 useEffect 상태관리 등을 만들어 보면 좋겠네요. 여기까지는 알고 있어야 React의 핵심을 다 이해하는 것이니까요.

=> 특히 상태 관리 시스템을 먼저 구현해보시면, 지금까지 만든 렌더링 시스템과 자연스럽게 연결될 것입니다.

=> 그리고 useMemo나 Memo등의 최적화 방식과 Context를 이용한 전역상태관리 Suspense등의 비동기 처리등 실제 React가 새롭게 추가한 역사를 따라가면서 core부터 최신 기능까지 원리를 이해해보면 좋겠네요.

수고하셨습니다. 다음 주차도 화이팅입니다! :)