https://getbootstrap.com/docs/5.1/components/spinners/
// movie.js actions 에 추가
// 사용자가 아직 검색이 끝나지 않았을 때 또 검색을 시도하면 return 시킨다.
if(state.loading) return
// 검색이 시작되면 기본메세지를 지워준다.
commit('updateState', {
message: '',
loading: true
})
// try catch 문에 finally 추가한다. 최종적으론 loading 이 끝나니까
finally {
commit('updateState', {
loading: false
})
}
// MovieList.vue
// no-result class 는 movies 의 결과에 따라서 생기고 사라진다.
// v-if 문으로 loading 중일 때 spinner 가 돌아가게 한다.
<template>
<div class="container">
<div
:class="{ 'no-result' : !movies.length }"
class="inner">
<div
v-if="loading"
class="spinner-border text-primary"></div>
<div
v-if="message"
class="message">
{{ message }}
</div>
<div
v-else
class="movies">
<MovieItem
v-for="movie in movies"
:key="movie.imdbID"
:movie="movie" />
</div>
</div>
</div>
</template>
export default {
components: {
MovieItem
},
computed: {
movies() {
// movie 모듈안에 movies
// 반응성 데이터를 유지하기 위해 computed
return this.$store.state.movie.movies
},
message() {
return this.$store.state.movie.message
},
loading() {
return this.$store.state.movie.loading
}
}
}
</script>
// 첫 화면이거나 검색에 실패 했을 때 회색화면에 텍스트를 띄운다.
<style lang="scss" scoped>
@import "~/scss/main";
.container {
margin-top: 30px;
.inner {
background-color: $gray-200;
padding: 10px 0;
border-radius: 4px;
text-align: center;
&.no-result {
padding: 70px 0;
}
}
.message {
color: $gray-400;
font-size: 20px;
}
.movies {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
}
</style>