[JS 개인과제] 피드백 수정-forEach, 변수 저장, dataset

Habin Lee·2023년 10월 30일
1

요약

  • for문을 forEach로 바꿀 수 있다.
  • 호출 결과를 변수에 저장하여 사용할 수 있다.
  • dataset을 사용하여 코드를 조금 더 간결하게 만들 수 있다.

완성작 미리보기

완성 코드

<script>
fetch('https://api.themoviedb.org/3/movie/top_rated?language=en-US&page=1', options)
   .then(response => response.json())
   .then((data) => {
      data.results.forEach(element => {
      document.querySelector('.row').innerHTML += `
      <div class="movie-card" id="${element.id}"token interpolation">${element.id}')">
         <div class="card">
             <img src=${`https://image.tmdb.org/t/p/w400` + element.backdrop_path} class="card-img-top" art="...">
             <div class="card-body">
             <h4 class="card-title" id="card-title">${element.original_title}</h4>
             <p class="card-text">${element.overview}</p>
             <p class="card-text"><small class="text-body-secondary">${`Rating : ` + element.vote_average}</small></p>
             </div>
          </div>
       </div>
       `;
      })
    })
   .catch(err => console.error(err));

document.addEventListener('DOMContentLoaded', () => {
    const payrollSearch = document.querySelector('#search-box');     

    function search() {
        // 카드 제목 element를 id 값(card-title)으로 가져오기
        const payrollTitle = document.querySelectorAll('.card-title');
        // 사용자가 입력한 검색어의 value값을 가져와 소문자로 변경하여 filterValue에 저장
        const filterValue = payrollSearch.value.toLowerCase();

        // payrollTitle 안에 있는 문자열을 for문으로 순회
        for (let i = 0; i < payrollTitle.length; i++) {
        // 현재 순회중인 payrollTitle의 textContent를 소문자로 변경하여 rows에 저장
        let rows = payrollTitle[i].textContent.toLowerCase();
        if(i === 0) {
         }
         const id = payrollTitle[i].parentElement.parentElement.parentElement.id;
         // rows가 filterValue를 포함하면 해당 title은 보여지게 하고, 그렇지 않으면 숨김
         if (rows.includes(filterValue)) {
             document.getElementById(id).style.display = '';
             } else {
                   document.getElementById(id).style.display = 'none';
                    }
             }
         }
         document.querySelector('#SearchBtn').addEventListener('click',search);
         // 검색어 입력 시 바로 필터링을 원할 때 클릭 이벤트 대신 keyup 사용 가능
         // payrollSearch.addEventListener('keyup', search);
        })
</script>

피드백

  1. search 함수에서 for문을 사용하여 DOM 요소들을 순회하고 있다. for문도 좋지만 forEach나 filter 같은 Array 메서드를 사용해보면 좋을 것 같다.
  2. document.getElementById(id)를 여러 번 호출하는 대신, 한 번만 호출하고 결과를 변수에 저장하여 재사용하는 것이 더 좋다.
  3. (개인적으로 보완하고 싶은 부분) ".parentElement.parentElement.parentElement" 보다 더 간결하게 코드를 짤 수 있는 방법은 없을까.

1. for문 -> forEach문

  • for문은 동기 방식이기 때문에 오류가 나면 오류가 난 위치 이후의 작업이 동작하지 않고 멈춰버리는 데에 반해 forEach문은 비동기 방식이기 때문에 멈추지 않고 동작하는 차이점이 있다.
  • forEach문은 가변적인 배열이나 리스트의 크기를 구할 필요가 없어 복잡한 반복문에 적합하며, index를 생성하여 접근하는 for문보다 수행 속도가 빠르다.
  • 데이터를 수정할 필요가 없을 때에는 for문보다 읽기전용으로 불러오는 forEach문이 효율적이다.
  • forEach문은 순서대로 정보를 가져오기 때문에 배열을 역순으로 탐색할 수 없는 단점이 있다.
document.addEventListener('DOMContentLoaded', () => {
    const payrollSearch = document.querySelector('#search-box');     

    function search() {
    // 카드 제목 element를 id 값(card-title)으로 가져오기
          const payrollTitle = document.querySelectorAll('.card-title');
          // 사용자가 입력한 검색어의 value값을 가져와 소문자로 변경하여 filterValue에 저장
          const filterValue = payrollSearch.value.toLowerCase();
      
          Array.from(payrollTitle).forEach((item, i) => {
          // 현재 순회중인 payrollTitle(item)의 innerHTML를 소문자로 변경하여 rows에 저장
               let rows = item.innerHTML.toLowerCase();
                    if(i === 0) {                        
                    }

               const id = payrollTitle[i].parentElement.parentElement.parentElement.id;
               // rows가 filterValue를 포함하면 해당 title은 보여지게 하고, 그렇지 않으면 숨김
               if (rows.includes(filterValue)) {
                    document.getElementById(id).style.display = '';
                  } else {
                        document.getElementById(id).style.display = 'none';
                    }
                })
            }

2. document.getElementById(id) 변수 저장

  • document.getElementById(id)를 if문에서 계속 호출하는 대신 변수로 저장하여 사용하니 훨씬 깔끔한 코드가 되었다.
const cardId = document.getElementById(id);
              console.log(id);
              if (rows.includes(filterValue)) {
                cardId.style.display = "";
              } else {
                cardId.style.display = "none";
              }

3. dataset 사용

  • 인터페이스의 읽기 dataset전용 속성은 요소의 사용자 정의 데이터 속성 ( ) HTMLElement에 대한 읽기/쓰기 액세스를 제공하고 각 속성에 대한 항목이 포함된 문자열 맵( )을 노출한다.
  • 기존 사용했던 코드는 parentElement를 사용하여 부모태그로 타고 올라가서 id값을 찾았었는데, 그 id 값을 daraset을 사용하여 바로 불러오도록 하였다.
  • card-title class에 해당하는 태그에 data-데이터이름="${element.id}"를 추가하고 아래에서 부모태그로 찾았던 id값을 dataset.데이터이름 으로 설정하여 바로 지정해준다.
<h4 data-num="${element.id}" class="card-title" id="card-title">${element.original_title}</h4>
...
const id = item.dataset.num;

수정한 완성 코드

<script>
fetch('https://api.themoviedb.org/3/movie/top_rated?language=en-US&page=1', options)
   .then(response => response.json())
   .then((data) => {
      data.results.forEach(element => {
      document.querySelector('.row').innerHTML += `
      <div class="movie-card" id="${element.id}"token interpolation">${element.id}')">
         <div class="card">
             <img src=${`https://image.tmdb.org/t/p/w400` + element.backdrop_path} class="card-img-top" art="...">
             <div class="card-body">
             <h4 data-num="${element.id}" class="card-title" id="card-title">${element.original_title}</h4>
             <p class="card-text">${element.overview}</p>
             <p class="card-text"><small class="text-body-secondary">${`Rating : ` + element.vote_average}</small></p>
             </div>
          </div>
       </div>
       `;
      })
    })
   .catch(err => console.error(err));

document.addEventListener('DOMContentLoaded', () => {
    const payrollSearch = document.querySelector('#search-box');     

    function search() {
        const payrollTitle = document.querySelectorAll('.card-title');
        const filterValue = payrollSearch.value.toLowerCase();

        Array.from(payrollTitle).forEach((item, i) => {
        let rows = item.innerHTML.toLowerCase();
        if(i === 0) {
         }
        
          const id = item.dataset.num;
          const cardId = document.getElementById(id);
                        console.log(id);
                        if (rows.includes(filterValue)) {
                          cardId.style.display = "";
                        } else {
                          cardId.style.display = "none";
                        }
                   }
               }
         document.querySelector('#SearchBtn').addEventListener('click',search);
        })
</script>

느낀 점

코드를 처음 작성했을 때는 잘한 것 같았는데, 막상 피드백을 받고 보니 코드를 더 간단히 쓸 수 있었는데 놓친 부분이 많다는 생각이 들었다. 변수에 저장하는 방법도 강의할 때 많이 들었지만 막상 구현을 하니 잘 보이지 않아서 잘 짜여진 코드를 자주 보고 배워야할 필요성을 느꼈다.
그리고 마지막에 사용한 dataset은 부모태그 대신 어떻게 사용하면 좋을지 고민하다가 팀원의 도움으로 사용하게 되었는데, 사실 dataset의 내용이 잘 나오지 않아 지금의 내 수준에서는 이해를 하기가 조금 힘들었다. 현재 이런 것을 사용하여 해결하였다는 내용은 적어놓고 앞으로 더 공부를 해봐야겠다.

1개의 댓글

comment-user-thumbnail
2023년 10월 31일

멋지십니다

답글 달기