Skip to content

Instantly share code, notes, and snippets.

@easylogic
Last active October 9, 2022 15:07
Show Gist options
  • Save easylogic/60ed94b94280db156f8d3f7cd9974421 to your computer and use it in GitHub Desktop.
Save easylogic/60ed94b94280db156f8d3f7cd9974421 to your computer and use it in GitHub Desktop.
Refactoring sapa

Sapa 의 몇가지 문제점(?)들을 다시 생각해본다.

  1. multi root elements

Sapa 는 기본적으로 컴포넌트 기반으로 설계가 되어 있기 때문에 컴포넌트는 하나의 element 를 root 를 가질 수 있다. multi elements 가 될려면 fragment 로 감싸야 하는다.

  1. fragment

vnode 를 처음 생성해서 dom 을 만들때는 괜찮지만 update 할 때가 문제다. 실체가 없는 상태로 update 를 진행해야한다. 본질적으로는 component 와 동일한 패턴으로 움직인다.

  1. 그 외는 모두 root 를 가진다.

  2. text node 는 children 을 가지지 않는다.


일단 multi root elements 를 가질려면 지금 구조에서 몇가지를 변경 해야한다.

  1. container 기준으로 children 만 제어한다.
  2. vnode 는 render 를 시작할 때 children: [vnode] 형태로 ㅅ ㅣ작한다.
  3. container 는 컴포넌트와 이어지지 않는다.
  4. child 하나는 특정 컴포넌트와 이어져있다.
  5. vnode 는 container 정보와 parent vnode 정보를 같이 가진다.
  6. vnode 는 순수하게 tree 형태로 연결되어 있어서 상위를 참조할 수 있다. ( parent 를 통해서)
  7. vnode 의 parent 가 없으면 모두 container 의 자식으로 인지한다.
  8. 렌더링 하는 방법은 children 을 그리는 방식과, 실제 vnode 를 업데이트 하는 방식으로 진행된다.
  9. 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();

  1. 모든 것을 work 단위로 만든다.
  2. work 는 work manager 에서 항상 실행을 하고 있다.
  3. 하나의 work 는 다음 work 를 지정할 수 있다.
  4. work 는 sibling 으로 순서대로 실행이 되고 sibling 이 없으면 parent 로 올라가서 다시 수행한다.
  5. 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();
}
@easylogic
Copy link
Author

vdom 트리 구조와 실제 dom 의 트리 구조를 어떻게 맞출지만 정의할 수 있으면 나머지는 그냥 될지도 모르겠다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment