부트캠프 프로젝트(完)/영화 검색 사이트(完)

[영화 검색 사이트 프로젝트] 4. 대소문자 구분x , 디바운싱, 리팩토링1

민ズl 2024. 10. 21. 15:49

이제 마지막...!!!

1. 대소문자 구분없이 검색

input의 value를 정규표현식 [a-zA-Z가-힣]으로 match메서드로 대소문자 구분없이 검색해서 join으로 합치기

*가-힣을 안넣어주면 한국어는 제외가 됨

* || [] 을 안하면 null이 반환되고, 그상태에서 join을 사용하면 에러가 뜸

const handleSearch = () => {
   let searchInputValue = searchInput.value;
   const regexValue = (searchInputValue.match(/[a-zA-Z가-힣]/gi) || []).join("");
   if (regexValue) getMovieData(regexValue);
};

 

2. 리팩토링

2-1. 실시간 검색시 스로틀링 또는 디바운싱을 사용해 최적화된 API 호출하기

 

  • 디바운싱: 사용자가 입력을 멈춘 후 일정 시간 후에 API를 호출
    예를 들어, 사용자가 검색어를 입력하다가 멈추면, 멈춘 후 300ms 후에 API가 호출
  • 스로틀링: 일정 시간 간격으로 API를 호출
    예를 들어, 사용자가 입력하는 동안 500ms마다 API를 호출하도록 설정

디바운싱 함수 function debounce를 만들어서, 사용자가 입력이 멈춘후 일정시간 후에(300ms) 특정 함수(handleSearch)를 호출

사용자가 다시 입력시 이전 타이머 초기화(clearTimeout)

특정 함수를 호출시 func.apply(this, args) 를 사용하여 원래 함수의 this와 인수를 그대로 전달

function debounce(func, delay) {
   let timer;
   return (...args) => {
      if (timer) clearTimeout(timer);
      timer = setTimeout(() => {
         func.apply(this, args);
      }, delay);
   };
}
  
const debounceSearch = debounce(handleSearch, 300);

 

2-2. index 페이지에 popular 영화 데이터를 랜덤으로 뿌리기

  1. 랜덤 숫자의 범위를 지정하여(Math.random()), 거기에 최댓값(32)에서 최솟값(1)을 뺀값(31)을 곱한후에 최솟값(1)을 더해준다
  2. 그리고 소수점(Math.random은 소수점을 반환)을 자연수로 바꿔주기(나는 Math.floor을 사용하여 소수점버림)
const randomNum = Math.floor(Math.random() * 31 + 1);
const url = `https://api.themoviedb.org/3/${
   keyword
   ? `search/movie?language=ko&query=${keyword}`
   : `movie/popular?language=ko&page=${randomNum}`
}`;

2-3. 상세 팝업에 데이터를 id값으로

원래 전에 작성한 코드는

전체 데이터를 받아와서 영화를 클릭시 해당 데이터를 뿌렸는데, 이에 성능저하 문제도 있고 좋지않음..ㅠㅠ

 

원래 코드를 git에 feature/detail-popup-all-data 브런치를 만들어서 저장해놓고,

현재 main 브런치에는 영화를 클릭시 해당 데이터를 받아와서 뿌리기로 함!

 

데이터를 가져오는 함수 파마리터에 videoId를 받아와서

export async function getMovieData(keyword, videoId) {...}

videoId 여부에 따라 데이터를 다르게 가져옴

=> videoId가 있을때는 datails API를

=> 없을때는 keyword가 있으면 search API / 없으면 popular API를 가져옴

export async function getMovieData(keyword, videoId) {
   const randomNum = Math.floor(Math.random() * 31 + 1);
   const url = videoId
      ? `${BASE_URL}/movie/${videoId}?${LANGUAGE_PARAM}`
      : `${BASE_URL}/${
         keyword
         ? `search/movie?${LANGUAGE_PARAM}&query=${keyword}`
         : `movie/popular?${LANGUAGE_PARAM}&page=${randomNum}`
      }`;
   ...
}

그리고 가져온 데이터에 videoId가 있으면 그대로 data를, 없으면 data.results로 가져옴

export async function getMovieData(keyword, videoId) {
   ...
   try {
      const res = await fetch(url, options);
      if (!res.ok) {
         throw new Error(res.status);
      }
   let data = await res.json();
   data = videoId ? data : data.results;
    ...
}

이후에 생각에 잠김... 

나는 getMovieDataElement(영화 리스트)는 그대로 보이고 팝업창은 그위에 DOM추가로 보여주고 싶다!

그래서 if문으로 구현!

try {
   const res = await fetch(url, options);
   if (!res.ok) {
      throw new Error(res.status);
    }
    let data = await res.json();
    data = videoId ? data : data.results;
    if (!videoId) {
      document.querySelector(".section__list").innerHTML = "";
      await getMovieDataElement(data);
    } else {
      createModal(data);
    }
  }

 

최종💫

export async function getMovieData(keyword, videoId) {
  const randomNum = Math.floor(Math.random() * 31 + 1);
  const url = videoId
    ? `${BASE_URL}/movie/${videoId}?${LANGUAGE_PARAM}`
    : `${BASE_URL}/${
        keyword
          ? `search/movie?${LANGUAGE_PARAM}&query=${keyword}`
          : `movie/popular?${LANGUAGE_PARAM}&page=${randomNum}`
      }`;
  try {
    const res = await fetch(url, options);
    if (!res.ok) {
      throw new Error(res.status);
    }
    let data = await res.json();
    data = videoId ? data : data.results;
    if (!videoId) {
      document.querySelector(".section__list").innerHTML = "";
      await getMovieDataElement(data);
    } else {
      createModal(data);
    }
  } catch (error) {
    console.error(error.message);
  }
}