이번 과제는 정말 쉽지 않았습니다.
각 파일이 어떤 역할을 하는지, 함수들이 어떤 순서로 동작하는지에 대한 개인적인 생각으로 설명이 부족하다 보니, 전반적인 구조를 파악하는 데 큰 어려움을 겪었습니다. 특히 함수 간 체이닝 구조나 render → updateAttributes → eventManager 같은 흐름이 왜 그렇게 구성되어 있는지에 대한 의문이 계속 들었습니다.
솔직히 말하면, GPT의 도움이 없었다면 구현 자체가 버거웠을 것 같습니다. 그만큼 제 실력의 한계를 느끼기도 했고, 동시에 앞으로 어떤 걸 더 공부해야 할지도 보였습니다. 항해가 끝난 뒤에는 제 코드뿐만 아니라 다른 사람들의 코드도 함께 리뷰해보며, SPA 구조에 대한 더 깊은 이해를 쌓고 싶습니다.
비록 설명은 부족했다고 느껴졌지만, 직접 SPA의 구조를 짜보고, JSX를 DOM으로 렌더링하는 과정을 구현해본 건 분명 큰 수확이었습니다. 다음 과제부터는 미리 일요일에 착수해서, 여유 있게 고민하고 구현할 수 있도록 준비하려고 합니다.
특히 만족스러운 구현
SPA 렌더링 구조에서 핵심이 되는 updateAttributes 함수를 아래와 같이 직접 구현했다
function updateAttributes(target, originNewProps, originOldProps) {
const newProps = { ...originNewProps };
const oldProps = { ...originOldProps };
// 이전 이벤트 핸들러 제거
Object.keys(oldProps).forEach((propName) => {
if (
propName.startsWith("on") &&
(!newProps[propName] || newProps[propName] !== oldProps[propName])
) {
const eventType = propName.toLowerCase().substring(2);
removeEvent(target, eventType, oldProps[propName]);
}
});
// 새로운 속성 추가 및 변경
Object.keys(newProps).forEach((propName) => {
if (propName.startsWith("on")) {
const eventType = propName.toLowerCase().substring(2);
addEvent(target, eventType, newProps[propName]);
} else if (propName === "className") {
target.setAttribute("class", newProps[propName]);
} else {
target.setAttribute(propName, newProps[propName]);
}
});
// 삭제된 속성 제거
Object.keys(oldProps).forEach((propName) => {
if (!(propName in newProps)) {
target.removeAttribute(propName);
}
});
}
이 함수는 다음과 같은 흐름으로 구성되어 있습니다
-> 이전 이벤트 핸들러 제거
-> 새로운 속성 및 이벤트 핸들러 반영
-> 삭제된 속성 제거
렌더링된 요소의 실제 DOM 속성과 이벤트를 동기화하는 데 중요한 역할을 하며, 명확한 순서와 책임 분리가 명확히 표시되어 있습니다.
특히 className 처리나 이벤트 핸들러 비교 후 조건적 제거는 실질적인 유지보수 편의성을 고려한 부분인것같습니다.
리팩토링이 필요한 부분
현재는 setAttribute 를 조건 없이 호출하고 있어, 기존 값과 같은 속성도 매번 업데이트됩니다.
이는 성능상 불필요한 DOM 조작을 유발할 수 있으며, 추후 diff 비교를 통해 값이 실제로 바뀌었을 때만 변경하도록 개선이 필요합니다.
이벤트 핸들러 등록/제거 로직도 반복적으로 등장하기 때문에, 이 부분을 별도의 헬퍼 함수로 추출해 코드 중복을 줄이고 가독성을 높일 수 있는 리팩토링 여지가 있습니다.
auth 객체로 관리하는 방식현재 renderElement → updateAttributes → appendChildren → eventManager로 이어지는 구조에서, 책임 분리가 잘 이루어진 편인지 궁금합니다.
updateElement.js의 updateAttributes와 createElement.js의 updateAttributes의 함수명이 왜 같게 진행되는지 두함수의 체이닝관계를 이해하지 못했습니다
for (const [key, value] of Object.entries(oldProps)) {
if (!(key in newProps)) {
if (key.startsWith("on")) {
const eventType = key.toLowerCase().slice(2);
removeEvent(target, eventType, value); // 이벤트 핸들러만 제거
} else {
target.removeAttribute(key); // 일반 속성 제거
}
}
}