render phase와 commit phase를 분리시켜보자.
updateVirtualDOM
함수를 저번 주차에 만들었었다. 하지만 이 코드는 함수 이름처럼 V-DOM만 update하지 않고, realDOM 까지 update해버린다.
내가 원하는 방식은 이거다.
updateVirtualDOM
→ updateRealDOM
realDOM에 영향을 주는 코드들은 다음과 같다.
updateVirtualDOM
이 완료가 된 후에 updateRealDOM
함수가 실행되야 하므로 저 밑줄친 부분을 어떤 곳에 저장해두었다가 인자 값으로 넘겨주면 되겠다고 생각했다.
Map을 사용해서 이런 식으로 구현해보았다.
export function updateVirtualDOM(root, oldNode, newNode, commitMap, index = 0) {
if (!oldNode) return commitMap.set('appendChild', { root, child: createVirtualDOM(newNode) });
if (!newNode) return commitMap.set('removeChild', { root, child: createVirtualDOM(root.childNodes[index]) });
if (oldNode.type !== newNode.type) return commitMap.set('replaceChild', { root, newChild: createVirtualDOM(newNode), oldChild: root.childNodes[index] });
if (
oldNode.type === 'TEXT_ELEMENT'
&& newNode.type === 'TEXT_ELEMENT'
&& oldNode.props.nodeValue !== newNode.props.nodeValue
) {
const newElement = createVirtualDOM(newNode);
return commitMap.set('replaceChild', { root, newChild: newElement, oldChild: root.childNodes[index] });
}
const oldProps = oldNode.props;
const newProps = newNode.props;
if (oldNode.type !== 'TEXT_ELEMENT' && oldNode.type !== 'FRAGMENT') {
commitMap.set('updateElement', { element: root.childNodes[index], newProps, oldProps });
}
const max = Math.max(oldProps.children.length, newProps.children.length);
for (let i = 0; i < max; i++) {
updateVirtualDOM(
oldNode.type === 'FRAGMENT' ? root : root.childNodes[index],
oldProps.children[i],
newProps.children[i],
commitMap,
i
);
}
return root;
}
export function updateRealDOM(commitMap) {
commitMap.forEach((value, key) => {
switch (key) {
case 'appendChild':
value.root.appendChild(value.child);
break;
case 'removeChild':
value.root.removeChild(value.child);
break;
case 'replaceChild':
value.root.replaceChild(value.newChild, value.oldChild);
break;
case 'updateElement':
getElementWithStyle(value.element, value.newProps, value.oldProps);
break;
}
});
}
하지만 이렇게 했을 때 에러가 띄워졌다.
getElementWithStyle
가 나중에 적용되다보니 이벤트 핸들러가 이상하게 인식해서 + 버튼을 눌러도 2 이상 올라가지 않는 현상이 발생했다.