이번 과제는 주어진 API를 활용하여 영화 검색 사이트를 만드는 것이었다. 이번 과제에서는 기존과는 달리 좀 더 체계적으로 접근하기 위하여 과제를 시작하기 전에 스케치를 사전에 진행하여 전체적인 구조를 잡고 과제를 진행하였다.
기본 요구사항과 특별 요구사항 중, 기본 요구사항을 먼저 만족하기 위한 구조를 잡았다.
/
: 구글처럼 home 화면으로 제목과 단 하나의 검색 바로만 구성/search
: 검색 결과를 보여주는 페이지/movie/:id
: id를 이용하여 해당 영화의 detail data에 접근하는 페이지이 부분은 가장 고민이었던 부분 중 하나이다. SPA의 장점을 극대화 하기 위하여 쿼리 정보를 내부에 저장하여 쿼리가 변경되면 데이터를 다시 fetch 하는 방식으로 구성을 할 지, 아니면 RouterLink
를 이용하여 직접 페이지를 변경하는 방식을 사용할 지 고민했다.
해당 프로젝트에서는 쿼리가 포함된 주소를 통해 접근했을 때, 해당 데이터에 바로 접근이 가능하고, bot이 데이터를 수집했을 때 알맞은 데이터를 보여줄 수 있도록 검색 엔진 최적화를 하고자 페이지를 직접 이동시키는 방식을 사용했다.
해당 페이지를 직접 이동시킬 때, 컴포넌트(Search)의 재렌더링이 발생할 줄 알고 우려하였다. 따라서 created를 통해 처음 컴포넌트가 렌더링 시 data를 fetch하도록 하였고, 페이지를 이동할 때 자동으로 created hook이 재실행 될 줄 알았는데 실행되지 않았다. (컴포넌트의 재렌더링 발생 X) 따라서 이 부분은 안심하고 적용할 수 있었다. 다만, watch
옵션을 통해 쿼리의 변경을 감지하여 data를 fetch하려고 할 때, 찾기 어려운 버그가 발생했었는데 이 부분은 하단부에 서술하도록 한다.
<script>
export default {
computed: {
query() {
return this.$router.query
}
},
watch: {
query() {
this.fetchData()
}
}
</script>
/search
에서 /movie/:id
이동시, 불필요한 watch가 발생하여 movie page에서 데이터를 fetch하기 전에 잘못된 쿼리로 데이터를 요청하고, isLoading
옵션이 오작동하는 문제이 부분은 과제를 전부 마친 후 테스트를 하면서 발견하였다.
movie detail 페이지로 이동할 때 path가 변경됨
created 가 화면에 컴포넌트가 구성되기 전에 호출되지만, fetchData
는 비동기 함수이므로 데이터를 받아올 때 까지 소요시간이 필요
이전 페이지의 watch 옵션으로 걸어 놓은 데이터 요청이 fail되고, isLoading = false
가 됨
따라서 화면에 데이터 없이 나머지 부분만 잠시 렌더링되고, 그 이후에 정상적으로 화면이 구성됨
요청에 대한 응답이 빠르면 해당 현상이 잘 확인되지 않지만 요청이 느리다면 발견하기 쉽다.
이 부분을 해결하기 위하여 여러 방식을 시도하였다.
전역 store의 isLoading을 처리하기 위하여 actions에 fetchData 함수를 구성하였는데, 이 부분의 로직에 console.log 찍어서 확인 → 아무런 문제가 없었음. 너무 단순했기 때문에
list → detail로 path 변경될 때 나타났던 문제점이기 때문에 해당 라우터의 fetchData에 console.log를 찍어보았는데 역시 문제가 발생하지 않았다.
가장 마지막으로 watch또한 fetchData 함수를 호출하기 때문에 이 부분에서 console.log를 찍어보았는데, 여기서 페이지 이동시에 fetchData를 호출하는 현상을 확인할 수 있었다. search?s=title&page=1
에서 movie/:id
로 이동하면서 this.$route.query
가 변경되고, 이에 따라서 페이지를 이동하기 전에 fetchData
함수가 호출되는 문제였다.
이 부분을 해결하기 위하여, path는 바뀌지 않기 때문에 watch 감지가 일어나도 해당 path가 아니면 데이터를 요청하지 않도록 처리하였다.
글로 쓰니까 금방 해결한 것 같은데 이거 처리하느라 거의 한시간 걸렸다….
비동기적으로 데이터를 불러오기 전에 paginator가 먼저 로딩되서 발생하는 문제
validation 코드를 잘 짜놔서 그런지 다행히도 금방 버그를 발견할 수 있었음
해결:
<Paginator
v-if="!isNaN(Number(apiData.totalResults))"
:total-items="Number(apiData.totalResults)"
:offset="5"
:post-per-page="10"
:base-url="`/search?&s=${query.s}&page=`"
/>
원래 생각으로는 데이터가 변경되면 자동으로 재렌더링이 발생하여 paginator가 다시 렌더링 되어야 하는데 그렇지 않았던 것 같다. 이 부분은 다시 한번 확인해야겠다.
dotenv-webpack
플러그인을 설치한 뒤, netlify에서 설정한 환경 변수를 읽을 수 있도록 systemvars: true 옵션을 주어 문제 해결이 가능했다. DotenvPlugin({ systemvars: true })
_redirects
파일을 구성하였다.뭔가 가독성 좋게, 그리고 해당 회사의 시그니처 컬러를 따서 만들어 보고자 하였는데, 꽤 괜찮게 뽑혀서 기분이 좋다.
이번 과제가 CSS에 중점을 둔 과제는 아니기 때문에 굳이 반응형 페이지를 구현할 필요는 없었지만, 저번 과제를 통해 CSS에 굉장히 약하다는 것을 깨닫고 다시 연습을 하고자 CSS에 신경을 썼다. 특히 flex 처리가 미흡했어서, 이 부분을 연습하면서 반응형 페이지 역시 구현하였다.
사실 react나 vue나 props로 데이터를 내려주는 것은 프로젝트의 크기가 커질 수록 버그의 발생 가능성을 높이기 때문에 모든 데이터를 전역 스토어로 관리하려고 하였으나, 해당 데이터는 현재 각 컴포넌트에서만 사용하기 때문에 굳이 전역 스토어를 구성하지 않았다. 다만, 모든 컴포넌트에서 공통적으로 사용하는 isLoading 식별자만 전역 스토어에서 관리하도록 하였다.
actions에 각 REST API의 주소마다 메서드를 만드는 것이 아닌, 해당 부분은 컴포넌트단에서 처리하도록 하고, actions는 fetchData 하나의 메서드만 두고, 콜백함수를 받도록하였다. fetchData
를 통해 api를 요청하게 되면, 자동으로 isLoading을 처리할 수 있도록 하였고, 다른 컴포넌트에서는 isLoaindg
에 대하여 신경 쓸 필요가 없도록 하였다. 이 부분이 클래스 설계 원칙(?) 은닉화? 그런 부분을 잘 지켰다고 생각했다. (오직 나만의 생각이다)
부트스트랩의 primary, secondary, danger… 등등의 옵션이 담긴 배열을 만들고, 랜덤한 인덱스가 호출되도록 하였다. 결과적으로는 이쁘게 잘 나왔다고 생각한다.
사전 스케치를 처음 해보았는데, 효율도 좋고 설계에 투자하는 시간 및 변경 시간을 줄일 수 있어서 결과적으로 일찍 과제를 끝낼 수 있었던 것 같다.
앞으로도 사전 스케치를 꼼꼼히 진행하여 더 능률을 높이는 방식으로 프로젝트를 진행해야겠다.