// index.tsx
class Test extends Dj.Component {
constructor(props: AttributeType){
super(props);
}
render() {
return (
<div>hello</div>
)
}
}
Dj.render(<Test />, root);
다음과 같이 class를 jsx 문법에 적용시키면 반환되는 vDOM 객체의 형태를 확인해보면 반환되는 type이 함수형태인것을 볼 수 있는데 사실 자바스크립트에서 class는 새로 생긴 개념이 아니라 특별한 함수이기 때문에 타입이 함수냐 아니냐로 컴포넌트를 판별할 수 있다.
하지만 함수로만 판단하면 일반 함수 또한 컴포넌트로 판단할 수 있기 때문에 부모 역할을 하는 Dj.component의 static 변수를 활용할 것이다.
// Dj/Component.ts
abstract class Component {
props: AttributeType;
abstract render(): IDom;
constructor(props: AttributeType){
this.props = props;
}
static DJ_COMPONENT = true;
}
export default Component;
이제 컴포넌트만 가지고 있는 특별한 변수를 사용해서 일반 노드인지 컴포넌트인지 구분하면 된다.
function vDomToNode(vDOM: IDom, container: Element | null, oldDOM?: IDom) {
// 컴포넌트일 경우
if(isComponentType(vDOM)){
componentNode(vDOM, container, oldDOM);
} else { // 일반노드일 경우
originNode(vDOM, container, oldDOM);
}
}
const isComponentType = (vDOM: IDom) => Object.getPrototypeOf(vDOM.type).DJ_COMPONENT;
그렇다면 컴포넌트인지는 구분했으니까 이 vDOM 객체를 이용하여 Node를 생성하면 되는데 일반노드를 생성하는 과정과는 조금 다르게 type 자체에 생성해야할 Node의 type이 존재하는 것이 아닌 생성자 함수가 포함된 함수가 존재하기 때문에 new 키워드를 사용하여 객체를 먼저 생성해야 한다.
const C = vDOM.type;
const component = new C(vDOM.attributes || {});
그리고 해당 객체가 가지고 있는 또 다른 vDOM 객체(주황색 박스)를 얻기위해 해당 객체의 render 메서드를 호출해준다.
const componentVDOM = component.render();
여기서 componentVDOM에 할당되는 값은 vDOM 객체이기때문에 또 다시 컴포넌트인지 일반노드인지 판별하고 일반노드일 경우 노드를 생성, 컴포넌트일 경우 객체를 생성하고 vDOM 객체를 얻어야한다.
그런데 지금까지 작성한 코드를 잘보면 그 과정들이 반복되도록 구성이 되어있고 그런 역할을 하는 함수가 vDomToNode함수이기 때문에 vDomToNode함수를 다시 호출해주면 컴포넌트도 렌더링 할 수 있게 된다.
function componentNode(vDOM: IDom, container: Element | null, oldDOM?: IDom) {
if(typeof vDOM.type === 'string') return;
const C = vDOM.type;
const component = new C(vDOM.attributes || {});
const componentVDOM = component.render();
vDomToNode(componentVDOM, container, oldDOM);
}
작성된 코드는 여기서(github) 확인하실 수 있습니다.