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

yoon Y·2022년 4월 25일
0
post-custom-banner

트리 구조 목록 구현

최상위 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
#프론트엔드
post-custom-banner

0개의 댓글