[리팩토링] 트리구조 목록 구현

yoon Y·2022년 4월 25일
0

트리 구조 목록 구현

최상위 ul
       ㄴli
       ㄴli
          ㄴul
             ㄴli
             ㄴli
             ㄴli

받아온 문서 목록 데이터를 받아서 최상위 ul에 PageItem를 렌더링하면서,
문서에 자식 문서들의 데이터가 있다면 재귀적으로 하위 목록들을 렌더링시켰다.

  createChildrenPages(childrenData, parentEl) {
    const childItemContainer = createElement('ul');
    addClass(childItemContainer, ['page_list', 'visible']);

    parentEl.$node.appendChild(childItemContainer);
    this.createPageItems(childrenData, childItemContainer);
  }

  createPageItems(data, itemContainer) {
    itemContainer.innerHTML = '';

    data.length &&
      data.map(({ id, title, documents }) => {
        const pageItem = new PageItem(itemContainer, { id, title });
        const haveChildren = documents.length;
        haveChildren && this.createChildrenPages(documents, pageItem);
      });
  }

  mounted() {
    const { data } = this.state;
    const $pageList = document.getElementById('root');
    this.createPageItems(data, $pageList);
  }

이벤트 설정 오류

문제점

ul에 걸 경우

  1. 하위 ul에도 이벤트가 걸렸기에 이벤트 버블링 발생
  2. 최상위 ul에 이벤트가 2번 걸림
    • 1뎁스의 PageItem이 2개인데, PageItem컴포넌트가 2번 생성되고 그때마다 $target으로 들어온 최상위 ul에 이벤트를 각각 걸기 때문이었다.

  setEvent() {
    console.log(this.$target);
    this.$target.addEventListener('click', e => {
      // e.stopPropagation();
      console.log(e.currentTarget);
    });
  }

각 아이템(li)에 걸 경우

setEvent() {
    this.$node.addEventListener('click', e => {
      // e.stopPropagation(); 
      console.log(e.target.closest('.page').dataset.id);
    });
  }
  1. 하위 li들에도 이벤트가 걸렸기에 이벤트 버블링 발생
    • e.stopPropagation()을 설정해주면 해결

최종 방법

각 아이템들에 이벤트를 걸고 e.stopPropagation()을 설정해줘도 됐지만,
아이템이 많아질 경우 너무 많은 이벤트가 걸린다

최상위 ul에 해당하는 PageList컴포넌트에서 부모태그인 target속성에 이벤트를 걸어 이벤트 위임을 사용했다.


// PageList.js

 setEvent() {
    this.addEventToTarget('click', '.page', e => {
      const { onClickRemove } = this.state;
      const { className } = e.target;
      const id = e.target.closest('.page').dataset.id;

      switch (className) {
        case 'page_name':
          push(`/pages/${id}`);
          break;
        case 'page_toggleButton':
          console.log('toggle');
          break;
        case 'page_removeButton':
          onClickRemove(id);
          break;
        case 'page_add_pageButton':
          console.log('add');
          break;
        default:
      }
    });
  }
}
profile
#프론트엔드

0개의 댓글