Sapa 의 몇가지 문제점(?)들을 다시 생각해본다.
- multi root elements
Sapa 는 기본적으로 컴포넌트 기반으로 설계가 되어 있기 때문에 컴포넌트는 하나의 element 를 root 를 가질 수 있다. multi elements 가 될려면 fragment 로 감싸야 하는다.
- fragment
vnode 를 처음 생성해서 dom 을 만들때는 괜찮지만 update 할 때가 문제다. 실체가 없는 상태로 update 를 진행해야한다. 본질적으로는 component 와 동일한 패턴으로 움직인다.
-
그 외는 모두 root 를 가진다.
-
text node 는 children 을 가지지 않는다.
일단 multi root elements 를 가질려면 지금 구조에서 몇가지를 변경 해야한다.
- container 기준으로 children 만 제어한다.
- vnode 는 render 를 시작할 때 children: [vnode] 형태로 ㅅ ㅣ작한다.
- container 는 컴포넌트와 이어지지 않는다.
- child 하나는 특정 컴포넌트와 이어져있다.
- vnode 는 container 정보와 parent vnode 정보를 같이 가진다.
- vnode 는 순수하게 tree 형태로 연결되어 있어서 상위를 참조할 수 있다. ( parent 를 통해서)
- vnode 의 parent 가 없으면 모두 container 의 자식으로 인지한다.
- 렌더링 하는 방법은 children 을 그리는 방식과, 실제 vnode 를 업데이트 하는 방식으로 진행된다.
- update 를 할 때는 multi root element 가 문제다.
다시 만드는게 나을려나?
let rootWork = null;
let currentWork = null;
function render(vnode, container) {
rootWork = {
dom: container,
children: [vnode]
}
currentWork = rootWork;
}
function renderingWork() {
if (!currentWork) return;
const oldChildren = currentWork?.alternate?.children;
renderingChildren(currentWork, oldChildren);
}
function renderingChildren(work, oldChildren) {
const container = work.dom;
const length = work.children.length - 1;
let i = 0;
let newWork = null;
let workQueue = [];
let prevWork = null;
while(i < length) {
const oldChild = oldChildren[i];
const newChild = work.children[i];
if (oldChild && !newChild) {
newWork = {
type: "DELETE",
parent: work,
index: i,
child: oldChild
}
} else if (!oldChild && newChild) {
newWork = {
type: "CREATE",
parent: work,
index: i,
child: newChild,
}
} else {
newWork = {
type: "UPDATE",
parent: work,
index: i,
oldChild,
newChild
}
}
workQueue.push(newWork);
if (i === 0) {
prevWork = newWork;
} else {
prevWork.sibling = newWork;
}
i++;
}
currentWork = workQueue[0];
}
renderWork();
- 모든 것을 work 단위로 만든다.
- work 는 work manager 에서 항상 실행을 하고 있다.
- 하나의 work 는 다음 work 를 지정할 수 있다.
- work 는 sibling 으로 순서대로 실행이 되고 sibling 이 없으면 parent 로 올라가서 다시 수행한다.
- 4에 의해서 하나의 root 는 자식을 모두 그리는 방식으로 운영된다.
일단 실행하는 방식 자체를 최대한 분리 해보자.
props 가 없는 상태로 어떻게 재조립 할 수 있을지를 생각해보자.
function renderingWork () {
if (currentWork.type === "DELETE") {
deleteChild(currentWork);
// unmount
// delete resource
// delete hooks
// destroy
} else if (currentWork.type === "CREATE") {
appendChild(currentWork);
// mount
// create instance
// create hooks
// initialize
} else if (currentWork.type === "UPDATE") {
updateProps(currentWork);
// update
// props update
// recreate children
}
renderingChildren();
}
vdom 트리 구조와 실제 dom 의 트리 구조를 어떻게 맞출지만 정의할 수 있으면 나머지는 그냥 될지도 모르겠다.