23/01/13_3차과제 리팩토링

강해경·2023년 1월 12일
1

Today I Learned

목록 보기
31/36
post-thumbnail

네.. 지난번 리팩토링 계획을 작성한지 꽤 오랜시간이 흘렀는데 4차과제와 리액트 강의를 듣느라 리팩토링이 늦어졌습니다. 리액트 강의 중간 이벤트 위임 개념이 나와서 더 이상 미루지말고 적용해보자 생각이 들어서 리팩토링을 했습니다!! 드디어..!!

🎊 이벤트

버블링과 캡처링

이벤트 발생 흐름은 1.캡처링 2.타깃 3.버블링 세 단계로 나눌 수 있습니다.

이벤트 캡처링은 이벤트가 발생했을 때 최상위 조상(window)에서 아래로 전파되는 것을 말하고 이후 이벤트 타깃요소에 도착한 후 중첩된 구조를 타고 가장 최상위 요소까지 이벤트가 전파되는 것을 이벤트 버블링 이라고 합니다.

이벤트 위임

A > B > C 요소가 중첩된 구조일 때 A에만 이벤트리스너를 걸어두었지만 B, C를 클릭했을 때도 이벤트가 발생하여 콘솔에 찍히는 것을 볼 수 있습니다. 콘솔에 찍힌 내용을 보면 event.currentTarget 은 항상 이벤트 핸들러가 할당된 요소이며 event.target 은 정확히 클릭한 요소를 나타내는 것을 알 수 있습니다. 이렇게 상위요소에 이벤트 핸들러를 할당하여 하위요소의 이벤트까지 제어하는 행위를 이벤트 위임이라고 합니다.

🔧 리팩토링(이벤트 위임 활용)

위 화면 == 목록을 불러와 각각의 리스트에 체크박스, 내용, 버튼들을 생성해주기 위해 작성했던 코드입니다.

리팩토링 전

for (let i = 0; i < TodoList.length; i++) {
    const li = document.createElement('li');
    li.dataset.id = TodoList[i].id;
    li.classList.add('list-group-item');

    const label = document.createElement('label');
    label.classList.add('form-check-label');

    const check = document.createElement('input');
    check.type = 'checkbox';
    check.addEventListener('change', renderCheckTodo);
    check.classList.add('form-check-input');

    const title = document.createElement('span');
    const _title = TodoList[i].title;
    title.append(_title);

    const btnEdit = document.createElement('button');
    btnEdit.innerText = 'edit';
    btnEdit.classList.add('btn', 'btn-outline-secondary', 'btn-sm');
    btnEdit.addEventListener('click', renderEditTitle);

    const btnDelete = document.createElement('button');
    btnDelete.setAttribute('class', 'btn-close');
    btnDelete.addEventListener('click', renderDeleteTodo);

    const _done = TodoList[i].done;
    check.checked = _done;
    if (_done) {
      label.classList.add('strike');
      li.classList.add('done');
    }
    const btns = document.createElement('div');
    btns.append(btnEdit, btnDelete);
    btns.classList.add('btns');
    label.append(check, title);
    li.append(label, btns);
    list?.appendChild(li);
  }

각 버튼과 체크박스에 이벤트리스너를 달아주기 위해 이렇게 for문 안에 createElement로 노드생성 후 클래스명과 이벤트리스너를 넣고 append를 했습니다. 계속해서 비슷한 구조가 반복되고 html구조도 눈에 잘 보이지 않는다는 단점이 있었습니다.

리팩토링 후

// index.js
const list = document.getElementById('todo-list');
// 가장 상위요소에 핸들러 할당
list.addEventListener('click', handler);
// 핸들러 함수 내부에 각 타깃(체크박스, 수정 및 삭제버튼)에 따라 분기처리
function handler(event) {
  if (event.target.type === 'checkbox') {
    renderCheckTodo(event);
  } else if (event.target.classList.contains('btn-close')) {
    renderDeleteTodo(event);
  } else if (event.target.classList.contains('btn-sm')) {
    renderEditTitle(event);
  }
}

// renderTodoList.js
const todoListHTML = TodoList.map((todo) => {
    return `
    <li data-id=${todo.id} class="list-group-item ${todo.done ? 'done' : ''}" >
      <label class="form-check-label ${todo.done ? 'strike' : ''}">
        <input type="checkbox" class="form-check-input" ${
          todo.done ? 'checked' : 'unchecked'
        }>
        <span>
        ${todo.title}
        </span>
      </label>
      <div class="btns">
        <button class="btn btn-outline-secondary btn-sm">edit</button>
        <button class="btn-close"></button>
      </div>
    </li>
    `;
  });
list.innerHTML = todoListHTML.join('');

가장 상위요소에만 이벤트 핸들러를 등록하여 하위 요소에는 별도로 이벤트리스너를 주지 않아도 되어서 api를 통해 불러온 데이터를 맵핑해 innerHTML에 구조가 보이게 작성해 주었으며, 버튼과 체크박스 등을 모두 포함하는 상위요소에 할당한 핸들러 함수에는 이벤트 타깃에 따라 실행되어야할 함수를 호출하여 좀더 간결하고 html구조를 한눈에 알아볼 수 있도록 리팩토링 해보았습니다.

✅ 느낀 점

사실 이번 리팩토링을 진행하면서 느낀 점은 이벤트 위임에 관련된 것 보다도... '리팩토링을 미루지 말자'입니다. 제가 작성한 코드와 구조임에도 불구하고 일정 시간이 흐르다 보니 기억이 나지 않는 부분이 꽤 있었습니다. 제가 작성한 코드를 제가 다시 보아도 이정도라면 다른사람이 읽게 되는 코드는 정말 가독성과 주석 등의 설명이 중요하겠다 생각이 들었습니다. 그리고 세세하게 고민하던 것도 많이 날라간 느낌이 들더라구요. 여튼 앞으로 좀 더 성실하게 리팩토링을 해야겠습니다ㅠㅠ 그리고 배운부분을 활용해서 리팩토링을 해보는 것을 개념을 이해하는데 많은 도움이 되는 거 같습니다 👍👍

0개의 댓글