이전 포스팅에 이어서 jsx에 diff를 적용해보는 과정으로 이번에는 컴포넌트 타입에 대한 처리를 해주려고 한다.
그전에 테스트를 위한 예시코드의 수정이 필요하며 테스트해볼 상황은 크게 두가지이다.
class Todo extends Dj.Component {
constructor(props: AttributeType){
super(props);
this.state = {
value: ''
}
this.handleInput = this.handleInput.bind(this);
}
handleInput(event: Event){
const { value } = event.target as HTMLInputElement;
this.setState({
...this.state,
value
})
}
render() {
const {books} = this.props;
return (
<div class="my-component">
<input type='text' onInput={this.handleInput} value={this.state.value} />
<button onClick={this.props.handleClick}>책추가</button>
<ul>
{books.map((book: IBook) => (
<li>
<input type="checkbox" class="toggle" checked={book.completed} />
{book.content}
</li>
))}
</ul>
</div>
)
}
}
class App extends Dj.Component {
constructor(props: AttributeType){
super(props);
this.state = {
books: [
{ id: 1, completed: false, content: 'star' },
{ id: 2, completed: true, content: 'rain' },
]
}
this.handleClick = this.handleClick.bind(this);
}
handleClick(event: MouseEvent) {
this.setState({
...this.state,
books: [
{ id: 1, completed: true, content: 'star' },
{ id: 2, completed: true, content: 'rain' },
{ id: 3, completed: false, content: 'you Dont know JS' },
]
})
}
render() {
const {books} = this.state;
return (
<div>
<p>이것은 컴포넌트 리렌더링을 위한 것</p>
<div>
<Todo books={books} handleClick={this.handleClick} />
</div>
</div>
)
}
}
Dj.render(<App />, document.querySelector('#root'));
우선, 컴포넌트인 경우 새로운 가상DOM으로 해당 컴포넌트 인스턴스를 생성하여 이전의 컴포넌트와 비교하는 함수를 호출하였다.
// Core/Dj/diff.ts
function nodeCompare(vDOM: IDom, container: Node | null , realDOM?: INode , idx: number = 0){
// 생략...
if(isComponentType(vDOM)){
componentCompare(vDOM, realDOM, idx);
return;
}
// 생략...
}
componentCompare함수는 새로운 가상DOM인 vDOM, 현재 화면에 렌더링되어있는 실제DOM인 realDOM 그리고 몇번째 자식인지를 구분하기 위한 idx를 매개변수를 받는 함수로 바벨에 의해 변환된 vDOM 객체를 컴포넌트 vDOM 객체로 한번 더 변환해주는 함수라고 생각하면 된다.
// componentCompare 함수
function componentCompare(vDOM: IDom, realDOM: INode, idx: number = 0){
// 과거랑 현재랑 같은 컴포넌트라면
const nextComponentVDOM = createComponent(vDOM);
nodeCompare(nextComponentVDOM, realDOM.parentNode, realDOM, idx);
}
vDOM: 바벨에 의해 변환된 객체로 해당 정보를 이용하여 컴포넌트 vDOM 객체로 만들어야 한다.
nextComponentVDOM: 실제 보여져야 할 노드들의 정보를 담고 있는 객체
// 컴포넌트용 vDOM 객체를 만드는 함수
export function createComponent(vDOM: IDom) {
if(typeof vDOM.type === 'string') return;
const C = vDOM.type;
const component = new C(vDOM.attributes || {});
const componentVDOM = component.render();
componentVDOM.DJ_COMPONENT = component; // component 식별을 위한 것
return componentVDOM;
}
함수 내부에서 컴포넌트 vDOM 객체로 변환해주는 작업을 거친 후 nodeCompare를 다시 호출해주면 책추가 버튼을 눌렀을 때, 정상적으로 diff알고리즘을 거친 후 필요한 요소만 변경할 수 있게된다.
한참 부족한 내용들이 많지만 일단 여기까지 작성해주고나면 내가 고려했던 상황들은 정상적으로 처리되는 것을 확인할 수 있었다.