TIL12. 바닐라JS로 컴포넌트 다루기

imloopy·2022년 4월 1일
0

Today I Learned

목록 보기
12/56

Today I Learned

오늘은 바닐라 자바스크립트로 컴포넌트를 만들고 다루는 법에 대하여 공부했다. 그러나 평소에 객체 지향적인 개념(추상화, 캡슐화, 상속, 다형성)에 대해 생소하고, 잘 쓸 일이 없다 보니, 개념을 알고 있으면서도 어떻게 써야하는지 잘 몰랐다. 특히 이번에 바닐라 자바스크립트로도 클래스로 컴포넌트를 추상화 한다면, 좀 더 체계적인 설계가 가능함을 알았다.

Vanilla JS로 DOM 다루기

순수한 자바스크립트로 DOM을 만들고 조작하는 법은 다음과 같다.

const button = document.createElement('button');
button.addEventlistener('click', () => {
  console.log('clicked');
}
document.querySelector('#app').appendChild(button);
  1. 우선 버튼을 만든다.
  2. 버튼에 이벤트를 등록한다.
  3. 버튼을 부모 엘리먼트의 자식에 등록하여 렌더링한다.

만약 우리가 100개의 버튼을 다룬다고 생각해보자.

const button1 = document.createElement('button');
const button2 = document.createElement('button');
//...
// 100개의 버튼 등록하기
document.querySelectorAll('button').forEach((button) => {
  button.addEventlistener('click', () => {
    console.log('clicked');
  }
});

100개의 버튼을 일일이 만들고, 그것을 각각 조작하기 위하여 이벤트를 등록하는 과정은 꽤나 힘들어질 것이다. 만약 버튼이 실시간으로 증가한다면, 이벤트 또한 실시간으로 등록해야한다. 좀 더 좋은 방법은 없을지 생각해본다.

Vanilla JS를 리액트처럼 다루기

리액트 컴포넌트 (함수형 말고 기존의 클래스형)는 크게 다음 세 가지로 구성되어 있다.
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}번 클릭했습니다.`;
  }
}
  1. 버튼클래스를 이용하여 버튼을 만들면, constructor()가 가장 먼저 실행이 되면서 상위 컴포넌트에 붙이고, state를 구성한다.
  2. document.createElement()를 이용하여 버튼을 만든다.
  3. render()함수를 통해 브라우저에 렌더링한다.
  4. 만약 state내부 데이터에 변경이 있다면, setState함수를 통해 state 내부 데이터를 조작하고, 바뀐 데이터로 렌더링한다.
  5. event를 컴포넌트마다 등록한다. 이 과정은 자동으로 이루어진다.

클래스를 만듬으로써 우리는 더 이상 100번의 element를 만들고, 이벤트를 등록할 필요가 사라졌으며, 데이터조작과 렌더링을 모두 신경써줄 필요 없이 데이터 조작만으로 바로 실시간으로 렌더링할 수 있게 되었다.

해결 과제

  1. 어디까지 추상화를 해야 하는지 (컴포넌트의 밑바닥부터 추상화하는지, 아니면 필요한 것만 추상화 하는지)
  2. 현재 단계에서 더 높은 추상화가 가능한지

0개의 댓글