[리팩토링] 베이스 컴포넌트 구현 및 적용

yoon Y·2022년 4월 25일
0

컴포넌트 구조

export default class Component {
  $node;   // 내 돔
  $target; // 부모 돔
  props;   // 부모에게 받은 데이터
  state;   // 나의 상태
  constructor($target, props) {
    this.$target = $target; // 부모 돔 저장
    this.props = props;     // props 저장
    this.setup();           // 초기 셋팅
    this.render();          // 렌더링(돔 생성)
    this.setEvent();        // 돔에 이벤트 부착
    this.fetch();           // 외부 데이터 불러온 후, 그 값으로 리렌더링
  }

  // 주로 상태를 셋팅한다
  setup() { 
    return;
  }

  // 내 돔을 생성한다
  createNode(tagName) { 
    this.$node = createElement(tagName);
  }

  // 내 돔이나 부모 돔에 삽입할 마크업을 한다.
  template() {
    return;
  }

  // 자식 컴포넌트를 연결한다.
  mounted() {
    return;
  }

  // 부모 돔에 이벤트를 건다(이벤트 위임이 목적)
  addEventToTarget(eventType, selector, callback) {
    const children = [...Array.from(this.$target.querySelectorAll(selector))];

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

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

  // 내 돔이나 자식 돔에 이벤트를 건다.
  setEvent() {
    return;
  }

  // template에 작성한 마크업을 내 돔이나 자식 돔에 삽입한다.
  // mounted()함수를 실행해 자식 컴포넌트를 연결한다.
  render() {
    if (this.$node) {
      this.$node.innerHTML = this.template();
      this.$target.appendChild(this.$node);
    } else {
      this.$target.innerHTML = this.template();
    }
    this.mounted();
  }

  // 자식 컴포넌트만 리렌더링 하는 경우의 로직을 작성한다.
  reRender() {
    return;
  }

  // 상태를 변경한 후 리렌더링을 한다.
  // 1. 내 컴포넌트 자체를 리렌더링 하는 경우
  // 2. 특정 자식 컴포넌트만 리렌더링 하는 경우 (두 번째 인자에 true설정)
  setState(newState, reRender = false) {
    this.state = { ...this.state, ...newState };
    reRender ? this.reRender() : this.render();
  }
}
 
  // 외부 데이터를 불러와서 setState를 실행시킨다.
  fetch()  {
     return;
  }

규칙

  • 가급적 부모 돔에 내 템플릿을 삽입하는 방법을 이용한다.
    • 내 돔(this.node)을 만들어서 부모 돔에 appendChild하는 방법은 리스트에 동적으로 item을 추가해야할 때만 사용한다.
  • 부모 컴포넌트에 자식 컴포넌트를 연결할 빈 태그를 만들어서 연결하고, data-component라는 속성을 넣어준다.

    template() {
      return `
      <div class="sidebar_contents_wrap">
        <div data-component="PageList" class="pages_outliner"></div>
        <div data-component="AddButton"></div>
      </div>
      `;
    }
  • 되도록 변경사항이 있는 자식 컴포넌트만 리렌더링 시킨다.

    • setState의 두번째 인자로 true를 넣어서 reRender메소드를 실행시키는 방법
  • 외부 영향을 미치는 코드나 메서드는 가상 상위 컴포넌트(페이지)에서 모든 로직을 다루고, 자식 컴포넌트에게 데이터와 핸들러 메소드를 넘겨준다.

  • 자식 컴포넌트의 메소드를 꺼내 써야할 때에는 mounted메소드에서
    새로운 프로퍼티를 선언해 자식 컴포넌트의 인스턴스를 저장한다.

    mounted() {
      const $pageList = this.$target.querySelector('[data-component="PageList"]');
      const $addButton = this.$target.querySelector('[datacomponent="AddButton"]',
      );
    
      // 리렌더링을 위해 메소드를 꺼내 써야할 자식 컴포넌트
      this.PageList = new PageList($pageList, {
        ...
      });
        
      // 리렌더링이 필요 없는 자식
      new AddButton($addButton, { 
        ...
      });
    }
profile
#프론트엔드

0개의 댓글