2차 공부/TIL

24.07.29 영화검색사이트 리팩토링

공대탈출 2024. 7. 29. 20:57
import { addEvent } from "./addEvent.js";
import { isSearchedData } from "./isSearched.js";

export function searchMovie() {
    const searchButton = document.querySelector(".searchButton");
    const searchInput = document.querySelector(".searchInput");
    const searchFunc = async function () {
        isSearchedData.isSearched = true;
        let movieArr = [];
        const options = {
            method: "GET",
            headers: {
                accept: "application/json",
                Authorization:
                    "Bearer Authorization",
            },
        };
        if (searchInput.value.length !== 0) {
            await fetch(
                `https://api.themoviedb.org/3/search/movie?query=${searchInput.value}&include_adult=false&language=en-US&page=1`,
                options
            )
                .then((response) => response.json())
                .then((response) => {
                    window.scrollTo({ top: 0, left: 0, behavior: "auto" });
                    let results = response.results;
                    movieArr.push(...results);
                    if (movieArr.length !== 0) {
                        const cardList = document.querySelector(".cardList");
                        cardList.innerHTML = "";
                        movieArr.forEach((movie) => {
                            const { id, title, overview, poster_path, vote_average } = movie;
                            const temp_html = `
                                    <div class="movieCard" id='${id}'>
                                        <img
                                            class="movieImage"
                                            src="https://image.tmdb.org/t/p/w500${poster_path}"
                                            alt="포스터 이미지"
                                        />
                                        <h3>${title}</h3>
                                        <p class='movieOverview'>${overview}</p>
                                        <p>Rating: <span>${vote_average}</span></p>
                                    </div>
                                `;
                            cardList.innerHTML += temp_html;
                        });
                    } else {
                        alert("검색어를 포함하는 영화가 존재하지 않습니다!");
                        searchInput.value = "";
                    }
                })
                .then(() => {
                    addEvent();
                });
        } else {
            alert("검색어를 입력해주세요!");
        }
    };
    searchButton.addEventListener("click", () => searchFunc());
    searchInput.addEventListener("keyup", (e) => {
        if (e.keyCode === 13) searchFunc();
    });
}

기존 검색코드이다.

export function addEvent() {
    let targetElements = document.querySelectorAll(".movieCard");
    targetElements.forEach((element) => {
        element.addEventListener("click", function () {
            alert(`movie id : ${element.id}`);
        });
    });
}

검색 후 데이터가 들어올 때마다 addEvent함수를 동기적으로 호출하는데, 이때 querySelectorAll로 호출된 모든 카드에 다시 이벤트리스너가 추가되는 것이 문제였다.

기존에 카드를 추가하는 방식인 innerHTML은 문자열로 추가되고 그것을 태그형식으로 parsing할 시간이 필요한데, 거기에 비동기적으로 addEventListener을 하면 적용이 안되는 문제가 있어 addEvent를 함수형식으로 모듈화시키고, 필요할 때마다 불렀던게 문제점이었다.

따라서 temp_html의 생성방식부터 innerHTML으로 추가하는 방식까지 모두 변경하여 addEventListener을 붙여줘야했다.

 

import { addEvent } from "./addEvent.js";

export function getSearchedMoviesByPageNum(res) {
    res.results.forEach((movie) => {
        const { id, title, overview, poster_path, vote_average } = movie;
        const cardList = document.querySelector(".cardList");
        let temp_div = document.createElement("div");
        temp_div.className = "movieCard";
        temp_div.id = `${id}`;
        temp_div.innerHTML += `
                                <img
                                    class="movieImage"
                                    src="https://image.tmdb.org/t/p/w500${poster_path}"
                                    alt="포스터 이미지"
                                />
                                <h3>${title}</h3>
                                <p class='movieOverview'>${overview}</p>
                                <p>Rating: <span>${vote_average}</span></p>
                                `;
        cardList.appendChild(temp_div);
        addEvent(id);
    });
    return;
}

변경한 코드 중 하나이다.

추가하는 카드를 감싸는 div태그를 createElement로 만들어주고, className, id를 달아준 뒤 그 안에 innerHTML으로 추가하였다.

카드를 만들고 난 뒤 cardList에 자식요소로 temp_div를 넣어주고, addEvent함수를 호출하여 이벤트리스너를 달아주었다.

 

addEvent함수도 변경점이 있다.

export function addEvent(id) {
    document.getElementById(`${id}`).addEventListener("click", () => {
        alert(`movie id : ${id}`);
    });
}

호출될 때 해당 영화의 id를 인자로 넣어주어 영화의 id값을 id로 가지고있는 element를 찾아내 addEventListener을 추가하는 방식이다.

 

이렇게 추가하니 이벤트리스너가 카드가 추가될 때 해당 카드에만 추가되어 버그를 고칠 수 있었다!