컴포넌트 구조 최적화(1)

yoon Y·2022년 3월 20일
0

Vanilla Project

목록 보기
8/13

리팩토링한 템플릿 컴포넌트 클래스로 기존 작업을 전환했다
기존에는 이벤트로 변경된 부분만 돔에 접근해 속성을 바꿔주었는데,
컴포넌트 디자인 패턴으로 프로젝트를 진행할거라면 상태에 의존해 리렌더링을 하도록 구현하는게 맞다는 생각이 들었다. 가상돔이 없으면 효율이 매우 떨어지지만.. 나중에 가상돔도 구현해봐야겠다

템플릿 컴포넌트


// tempalte/Component.ts
export default class Component<P, S> {
  $target: Element;
  props: P;
  state?: S;
  constructor($target: Element, props?: P) {
    this.$target = $target;
    this.props = props;
    this.setup();
    this.render();
    this.setEvent();
  }

  setup() {
    return;
  }

  mounted() {
    return;
  }

  template() {
    return '';
  }

  render() {
    this.$target.innerHTML = this.template();
    this.mounted();
  }

  setEvent() {
    return;
  }

  setState(newState: S) {
    this.state = { ...this.state, ...newState };
    this.render();
  }

  addEventToTarget(
    eventType: string,
    selector: string,
    callback: (e: Event) => void,
  ) {
    const children = [...Array.from(this.$target.querySelectorAll(selector))];

    const isTarget = (target: EventTarget): boolean | Element => {
      if (target instanceof HTMLElement) {
        return children.includes(target) || target.closest(selector);
      }
    };

    this.$target.addEventListener(eventType, event => {
      if (!isTarget(event.target)) return false;
      callback(event);
    });
  }
}

적용


// HexColor.ts
class HexColors extends Component<undefined, HexColorsState> {
  setup() {
    this.state = { hexCode: '#ffffff' };
  }

  template() {
    return `
    <div data-name="hex-colors_container" style="background:${this.state.hexCode};">
      <div data-name="contents"></div>
      <div data-name="change-button-wrap"></div>
    </div>
    `;
  }

  mounted() {
    const $contents = this.$target.querySelector('[data-name="contents"]');
    const $button = this.$target.querySelector(
      '[data-name="change-button-wrap"]',
    );

    new Contents($contents, this.state);
    new ChageButton($button, { onClick: this.handleClickButton.bind(this) });
    return;
  }

  getRandomColor() {
    return '#' + Math.round(Math.random() * 0xffffff).toString(16);
  }

  handleClickButton() {
    const backColorCode = `linear-gradient( to left, ${this.getRandomColor()}, ${this.getRandomColor()} )`;
    this.setState({ hexCode: backColorCode });
  }
}

export default HexColors;
profile
#프론트엔드

0개의 댓글