과제 체크포인트
배포 링크
https://jangrubin2.github.io/front_6th_chapter1-2/
기본과제
가상돔을 기반으로 렌더링하기
- createVNode 함수를 이용하여 vNode를 만든다.
- normalizeVNode 함수를 이용하여 vNode를 정규화한다.
- createElement 함수를 이용하여 vNode를 실제 DOM으로 만든다.
- 결과적으로, JSX를 실제 DOM으로 변환할 수 있도록 만들었다.
이벤트 위임
- 노드를 생성할 때 이벤트를 직접 등록하는게 아니라 이벤트 위임 방식으로 등록해야 한다
- 동적으로 추가된 요소에도 이벤트가 정상적으로 작동해야 한다
- 이벤트 핸들러가 제거되면 더 이상 호출되지 않아야 한다
심화 과제
Diff 알고리즘 구현
- 초기 렌더링이 올바르게 수행되어야 한다
- diff 알고리즘을 통해 변경된 부분만 업데이트해야 한다
- 새로운 요소를 추가하고 불필요한 요소를 제거해야 한다
- 요소의 속성만 변경되었을 때 요소를 재사용해야 한다
- 요소의 타입이 변경되었을 때 새로운 요소를 생성해야 한다
과제 셀프회고
react를 사용하지 않고 virtual node를 만들어내고 그것을 DOM요소로 생성하는 과정에서 직접 불편함을 느끼며 왜 리액트가 만들어졌는지 알 수 있었습니다.
기술적 성장
virtual node를 생성할 때 children이 중첩 배열로 넘어오는 경우가 많은데 그것을 평탄화해주고 VNode를 렌더러가 처리하기 쉽게 일관된 형태로 변환해야한다는 사실을 알게됨 대부분 로직이 정규화를 거치고 falsy값 제거하고의 반복이었다.
function updateAttributes($el, props) {
if (!props) return;
Object.entries(props).forEach(([key, value]) => {
if (key === "className") {
$el.setAttribute("class", value);
} else if (key.startsWith("data-")) {
$el.setAttribute(key, value);
} else if (key.startsWith("on")) {
addEvent($el, key.slice(2).toLowerCase(), value);
} else if (key === "selected" && $el.tagName === "OPTION") {
$el.selected = !!value;
return;
} else if (["checked", "disabled", "readOnly"].includes(key)) {
$el[key] = !!value;
if (value) {
$el.setAttribute(key, "");
}
return;
} else {
$el.setAttribute(key, value);
}
});
}
updateAttributes 함수에서 매번 이렇게 조건문 추가해줘야하는건가요? 다른 방법이 있는지 궁금하네요
코드 품질
const eventTypes = [];
const elementMap = new Map();
// 실제 이벤트 발생
const handleEvent = (e) => {
const handlerMap = elementMap.get(e.target);
const handler = handlerMap?.get(e.type);
// 실행
if (handler) handler.call(e.target, e);
};
export function setupEventListeners(root) {
eventTypes.forEach((eventType) => {
root.addEventListener(eventType, handleEvent);
});
}
export function addEvent(element, eventType, handler) {
if (!eventTypes.includes(eventType)) eventTypes.push(eventType);
const handlerMap = elementMap.get(element) || new Map();
if (handlerMap.get(eventType) === handler) return;
handlerMap.set(eventType, handler);
elementMap.set(element, handlerMap);
}
export function removeEvent(element, eventType, handler) {
const handlerMap = elementMap.get(element);
if (!handlerMap) return;
if (handlerMap.get(eventType) === handler) handlerMap.delete(eventType);
if (handlerMap.size === 0) elementMap.delete(element);
else elementMap.set(element, handlerMap);
}
이벤트 위임 기반의 이벤트 관리 시스템 구현 이벤트를 중복해서 생성하면 안되기 때문에 html element, 이벤트 타입을 각각 키로둬서 중첩 문제점을 찾아보니 위와 같이 map으로 구현하면 메모리 누수 위험이 있다고 들었습니다. elementMap이 Map이라서 DOM이 제거돼도 강하게 참조되기 때문이라는데 weak map을 사용하면 해결될 문제일까요?
학습 효과 분석
virtual DOM을 직접 만들고 리액트의 기본원리에 대해 깊게 탐구할 수 있었다. 실무에서 적용할 일이 있을까...? 하지만 준일 코치님이 말씀하신대로 리액트를 사용하지 못하는 상황에서 유용하게 쓸 수 있을듯 하다
과제 피드백
이걸 과연 현업에서 쓸 수 있을까...? 과제를 하면서 좋았던 부분은 이런 과제를 하지 않았으면 가상돔에 대해서 평생 뜯어보지 않았을 것 같다.
리뷰 받고 싶은 내용
eventManager의 전반적인 내용에 대한 피드백을 원합니다. weakMap을 사용하는 것 외에 문제가 될만한 부분이나 방식이 적절한지에 대해 의구심이듭니다.
과제 피드백
루빈님 고생하셨어요~ 커밋로그를 보니 그간 꽤나 힘든 시간을 보낸걸 함께 느낄수 있었는데요.. 아쉽게 전체적으로 추가 구현이 필요한 부분들이 아직은 많이 남아있는 것 같아요. 다른 분들 잘 구현하신 분들 코드도 살펴보시고 질문해보면서 구현 꼭 끝까지 마무리해보셨으면 좋겠네요.
고생하셨고 다음 주에는 꼭 통과하는걸 목표로 하시죠! 화이팅입니다~