이전의 vue에서는 data fetch 로직을 주로 created()
나 mounted()
에 넣어서 필요한 data를 가져왔습니다.
Nuxt에서는 server-side에서 페이지나 컴포넌트에 필요한 데이터를 불러올 수 있도록 하는 두 가지 훅을 사용할 것을 권장하고 있습니다.
- asyncData
- fetch (Nuxt 2.12 이후 버전)
이 둘은 모두 server-side rendering에서 사용되는 data fetching hook이지만 차이점이 있습니다.
Nuxt의 lifecycle에서 보게 되면 fetch()
는 created()
가 실행된 후 즉, server-side에서 component instance가 생성된 후 불리게 됩니다. 반면에 asyncData()
는 created()
불리기 이전에 실행됩니다. 이 호출 시점의 차이 때문에 fetch()
에서는 this의 사용이 가능하고 asyncData()
에서는 this 사용이 불가능합니다.
둘의 차이점을 정리해보면 다음과 같습니다.
export default {
async asyncData(context) {
const data = await context.$axios.$get(...)
// `todos` 는 data() 안에 선언되어 있지 않아도 됩니다.
return { todos: data.Item }
// `todos` 는 local data에 병합(merge)됩니다.
}
}
export default {
data: () => ({
todos: []
}),
async fetch() {
const { data } = await axios.get(...)
// `todos` data()에 선언되어 있어야합니다.
this.todos = data
}
}
fetch hook은 Nuxt 2.12에서 많은 변화가 있었습니다. https://nuxtjs.org/announcements/understanding-how-fetch-works-in-nuxt-2-12/
fetch 훅에 대해서 더 알아보도록 하겠습니다.
fetch hook과 함께 this.$fetchState
를 활용할 수 있는데 fetchState는 세가지 property를 가집니다.
1. pending
2. error
3. timestamp (cache와 관련해 activated hook에서 사용)
이를 이용하면 쉽게 로딩뷰와 에러 뷰를 구현할 수 있습니다.
<template>
<div>
<p v-if="$fetchState.pending">Fetching mountains...</p>
<p v-else-if="$fetchState.error">An error occurred :(</p>
<div v-else>
...
</div>
</div>
</template>
<script>
export default {
data: () => ({
}),
async fetch() {
}
}
</script>
fetch 훅을 사용해서 data를 불러오게 되면 처음 페이지 로딩할 때 chrome의 network tab에서는 해당 내용을 확인할 수 없었습니다. 이유를 확인해보니 network tab은 브라우저에서 client-side에서 발생하는 network 활동을 감지하기 때문에 server-side에서 실행된 fetch의 동작은 확인할 수 없는 것이였습니다.
fetchOnServer: false
로 설정하게 되면 fetch hook을 client-side로 변경시킬 수 있습니다.
async fetch () {
},
fetchOnServer: false,
data: () => ({
}),
Nuxt 2.12이후에 fetch는 $fetch를 통해 method처럼 사용할 수 있습니다.
이전에는 page에 필요한 data를 다시 불러오기 위해서 data fetch 로직을 반복하거나 함수로 분리해야 했는데, $fetch를 이용하면 이를 더욱 쉽게 구현할 수 있습니다.
export default {
methods: {
refresh() {
this.$fetch()
}
}
}
프로젝트 진행 중 브랜드마다 style을 다르게 적용해야하는 경우가 있었는데, 이를 위해 fetch hook에서 theme api를 호출하고 css variable을 설정하여 theme color를 페이지에 적용시킨 코드입니다.
<template>
<div :style="cssVariable">
<nuxt />
</div>
</template>
<script>
export default {
async fetch () {
const {
main_color: mainColor,
sub_color: subColor,
} = await this.fetchBrandTheme()
this.cssVariable = {
'--main': mainColor,
'--sub': subColor,
}
},
data: () => ({
cssVariable: {
'--main': '',
'--sub': '',
},
}),
...
}
</script>
fetch()는 v2.12 이후 this 사용이 가능해지면서 아주 편리한 hook이 된 것 같습니다. 앞으로 Nuxt 프로젝트에서 data fetch logic 구현할 때 많은 도움이 될 것 같습니다 👍🏻
참고자료📕
https://nuxtjs.org/announcements/understanding-how-fetch-works-in-nuxt-2-12/
https://nuxtjs.org/docs/features/data-fetching/#accessing-the-fetch-state
nuxt만의 이런 생명주기 함수가 있는 줄 처음 알았네요!
좋은 글 감사합니다! 🙂