개인 프로젝트로 바닐라 자바스크립트 만을 이용하여 TMDB에서 정보를 받아다가 영화를 검색해서 포스터, 제목, 간략한 정보 등을 알려주는 사이트를 제작했다.
구현 과정에서 fetch를 통하여 정보를 긁어오는데, 페이지가 시작 될 때 검색 가능한 영화 목록의 타이틀을 노출 시켜주기 위해 start함수안에서 한 번, 그리고 검색 버튼을 눌렀을 때 input의 value값과 영화의 title을 비교해주기 위한 정보를 가져올 때 search함수 안에서 한 번, 이렇게 fetch를 두번 실행 하여 정보를 가져왔다.
function start() {
fetch(
"https://api.themoviedb.org/3/movie/top_rated?language=en-US&page=1",
options
)
.then((response) => response.json())
.then((response) => movieList(response))
.catch((err) => console.error(err));
console.log(response);
return;
}
//검색 시 작동 함수, fetch로 api를 긁어옵니다.
function search() {
fetch(
"https://api.themoviedb.org/3/movie/top_rated?language=en-US&page=1",
options
)
.then((response) => response.json())
.then((response) => cpTxt(response))
.catch((err) => console.error(err));
return;
}
각각의 함수가 실행되면 fetch를 통해서 api정보값을 가져오고 가져오는데에 성공했을 경우 각각 response을 인자로 movieList함수와 cpTxt함수를 실행하는 구조이다.
구조상 검색 버튼을 누를 때마다 fetch가 발생하여 지나치게 통신이 많이 이루어지는 것 같았고, 함수 역시 비슷한 내용이 두 번씩이나 실행되어 좋아보이지 않았다.
const fetchApi = async () => {
let fetchInfo = await fetch(
"https://api.themoviedb.org/3/movie/top_rated?language=en-US&page=1",
options
);
let newFetchInfo = await fetchInfo.json();
return newFetchInfo.results;
};
//fetchApi에서 가져온 Api정보를 담아둡니다.(새로고침 시 호출 )
const start = async () => {
fetchApiInfo = await fetchApi();
movieList();
};
구조를 바꾸어서 페이지가 열릴 때 start 함수가 실행되도록 하였다. 그리고 fetch로 받아온 정보 중 필요한 것들을 fetchApiInfo 변수 안에 담아주었다.
아래의 함수들도 기존 인자로 받아서 사용하던 구조를
const movieList = async () => {
let res = await fetchApiInfo;
let div = document.createElement("div");
div.className = "movie-list";
$pre_div.append(div);
let h3 = document.createElement("h3");
h3.innerHTML = "<영화 순위>";
div.append(h3);
let mvList = res.map(function (results, i) {
let mv_namelist = results["title"];
return `${i + 1}. ${mv_namelist}`;
});
for (let i = 0; i < mvList.length; i++) {
let p = document.createElement("p");
p.innerHTML = `${mvList[i]}`;
div.append(p);
}
return;
};
이런식으로 res 변수 안에 fetchApiInfo를 담아서 해결하였다.
fetchApi 함수 안에 console.log를 추가하여 확인 해 본 결과 정상적으로 페이지가 시작될 때 처음 1회만 작동하고 그 후로는 재 작동하지 않는걸 확인할 수 있었다.
다만 코드를 수정하면서 조금 헷갈렸던 부분이 async의 return 값이었다. 처음에는 fetchApi함수에서 return되는 값인 newFetchInfo.results값을 바로 사용하려고 하자 오류가 발생하였는데 확인해보니 async함수를 통해서 return된 값은 promise객체로 바뀌어서 나왔기 때문이었다.
fetchApi 함수 내에서 newFetchInfo.results값을 console.log로 찍어보고 함수 바깥에서 fetchApi()값을 찍어보았을 때,
전자는 제대로 출력되는 반면 후자는 promise객체로 감싸여서 찍히는걸 볼 수 있었다.
분명히 배웠던 부분인데 실제 코드를 작성하는 과정에서 마주하자 조금 당황스러웠다.
해결은 fetchApi()값을 async함수 내에서 받아서 다른 변수에 집어넣어서 해결했다.
const start = async () => {
fetchApiInfo = await fetchApi();
movieList();
};
또 곤욕스러웠던게 있었는데,
다름아닌 onclick이었다.
영화 포스터 이미지를 클릭하면 해당 이미지에 속한 id값과 title값을 alert창으로 띄워주는 구조를 만들고 있었는데, 아무리 해도 인자값으로 id와 title이 정상적으로 넘어가지를 않았다.
function createCard(res, i) {
let div = document.createElement("div");
div.className = "movie-card";
div.id = res[i]["id"];
$mv_cardList.append(div);
let id = div.id;
let t = res[i]["title"];
let img = document.createElement("img");
img.src = `https://image.tmdb.org/t/p/w300${res[i]["poster_path"]}`;
img.setAttribute("onclick", `imgBtn(${id}, ${t})`);
div.append(img);
// 생략--------------------
return;
}
const imgBtn = (id, t) => {
return alert(`${t}의 id값은 ${id}입니다.`);
};
여기서 imgBtn()함수 안에 id값과 t값을 넣어주고 싶었는데
Uncaught SyntaxError: missimg ) after argument list
라는 오류가 발생하였다.
조금 찾아보니 따옴표가 제대로 들어가지 않아서 발생한 오류라고 했다.
백틱 안에 함수를 선언해서 ${}로 감싸주었으나 텍스트로 들어가게 되면서 ${}도 따옴표로 다시 한 번 감싸주어야 했다.
img.setAttribute("onclick", `imgBtn('${id}', '${t}')`);
혹은 백틱을 따옴표 대신 사용한다면 오류가 발생하지만 역슬래시와 백틱을 통해서도 동일한 효과를 가질 수 있었다.
img.setAttribute("onclick", `imgBtn(\`${id}\`, \`${t}\`)`);
setAttribute를 통해서 작성을 해보는 것이 처음이라 함수를 집어넣었는데 작동을 안하거나 인자가 제대로 불러와지지 않아 당황스러웠지만 고생한만큼 확실하게 방법을 알았다.