오늘은 바닐라 자바스크립트로 컴포넌트를 만들고 다루는 법에 대하여 공부했다. 그러나 평소에 객체 지향적인 개념(추상화, 캡슐화, 상속, 다형성)에 대해 생소하고, 잘 쓸 일이 없다 보니, 개념을 알고 있으면서도 어떻게 써야하는지 잘 몰랐다. 특히 이번에 바닐라 자바스크립트로도 클래스로 컴포넌트를 추상화 한다면, 좀 더 체계적인 설계가 가능함을 알았다.
순수한 자바스크립트로 DOM을 만들고 조작하는 법은 다음과 같다.
const button = document.createElement('button');
button.addEventlistener('click', () => {
console.log('clicked');
}
document.querySelector('#app').appendChild(button);
만약 우리가 100개의 버튼을 다룬다고 생각해보자.
const button1 = document.createElement('button');
const button2 = document.createElement('button');
//...
// 100개의 버튼 등록하기
document.querySelectorAll('button').forEach((button) => {
button.addEventlistener('click', () => {
console.log('clicked');
}
});
100개의 버튼을 일일이 만들고, 그것을 각각 조작하기 위하여 이벤트를 등록하는 과정은 꽤나 힘들어질 것이다. 만약 버튼이 실시간으로 증가한다면, 이벤트 또한 실시간으로 등록해야한다. 좀 더 좋은 방법은 없을지 생각해본다.
리액트 컴포넌트 (함수형 말고 기존의 클래스형)는 크게 다음 세 가지로 구성되어 있다.
1. state
2. setState
3. render
이 세가지를 조합하여 컴포넌트를 체계적으로 관리한다. 바닐라 JS의 클래스를 사용하여 비슷하게 동작할 수 있도록 해보자.
class Component {} // 상속을 위한 컴포넌트, 추후에 더 높은 추상화 클래스 구현
import { Component } from "./Component.js";
class Button extends Component {
constructor({ $target, initialState, text = "" }) {
super();
this.state = initialState;
this.button = document.createElement("button");
this.text = text;
$target === null || $target === void 0
? void 0
: $target.appendChild(this.button);
this.render();
this.setEvent();
}
setState(nextState) {
this.state = Object.assign({}, nextState);
this.render();
}
render() {
this.button.textContent = this.text;
}
setEvent() {}
}
class ToggleButton extends Button {
constructor({ $target, initialState, text = "" }) {
super({ $target, initialState, text });
}
setEvent() {
this.button.addEventListener("click", () => {
console.log("clicked");
this.setState({
toggled: !this.state.toggled,
clickCount: this.state.clickCount + 1,
});
console.log(this.state);
});
}
render() {
this.button.textContent = `${this.state.clickCount}번 클릭했습니다.`;
}
}
constructor()
가 가장 먼저 실행이 되면서 상위 컴포넌트에 붙이고, state
를 구성한다.document.createElement()
를 이용하여 버튼을 만든다.render()
함수를 통해 브라우저에 렌더링한다.state
내부 데이터에 변경이 있다면, setState
함수를 통해 state
내부 데이터를 조작하고, 바뀐 데이터로 렌더링한다.클래스를 만듬으로써 우리는 더 이상 100번의 element를 만들고, 이벤트를 등록할 필요가 사라졌으며, 데이터조작과 렌더링을 모두 신경써줄 필요 없이 데이터 조작만으로 바로 실시간으로 렌더링할 수 있게 되었다.