Nuxt - Data Fetching
์์ํ๋ฉฐ
Nuxt ๊ณต์ ๋ฌธ์์ ์๋ Data Fetching w์ ๊ด๋ จ๋ ๋ด์ฉ์ ๋ฒ์ญํ ๊ธ์ ๋๋ค.
Data Fetching
Nuxt์์๋ API๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ 2๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
fetch๋ฉ์๋์asyncData๋ฉ์๋๋ฅผ ์ฌ์ฉํด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
Nuxt๋ client-side ์ดํ๋ฆฌ์ผ์ด์
์์ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ฉํ๊ธฐ ์ํ ์ ํต์ ์ธ Vue์ ํจํด์ ์ ๊ณตํฉ๋๋ค. (์ปดํฌ๋ํธ์ mounted() ํ
์์๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ)
๊ทธ๋ฌ๋ ๋ฒ์ฉ์ ์ผ๋ก๋ server-side ๋ ๋๋ง ๋์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋๋ก Nuxt์ ํน์ ํ
๋ค์ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
์ด๋ ๊ฒ ํ๋ฉด ํ์ด์ง์ ํ์ํ ๋ชจ๋ ๋ฐ์ดํฐ์ ํจ๊ป ํ์ด์ง๋ฅผ ๋ ๋๋ง ํ ์ ์์ต๋๋ค.
Nuxt์ ๋น๋๊ธฐ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ฉํ๋ ๋๊ฐ์ง hooks:
asyncData: ์ด ํ ์ page ์ปดํฌ๋ํธ์์๋ง ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค. ์ด ํ ์ client-side ๋ ๋๋ง ๋์ ๋ก๋ฉ๋๋ ๊ณต๊ฐ์ ํ์ํ์ง ์์ต๋๋ค.
๋์ ์, ์ด ํ ์ ํด๊ฒฐ๋ ๋๊น์ง ํ์ด์ง ์ด๋์ ๋ง๊ณ ์คํจํ ๊ฒฝ์ฐ ์๋ฌ ํ์ด์ง๋ฅผ ๋ณด์ฌ์ค๋๋ค.
fetch(Nuxt 2.12+): ์ด ํ ์ ๋ชจ๋ ์ปดํฌ๋ํธ์์ ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ก๋ฉ ์ํ(client-side ๋ ๋๋ง ์ค)์ ์๋ฌ๋ฅผ ๋ ๋๋ง ํ๊ธฐ ์ํ shortcuts๋ฅผ ์ ๊ณตํฉ๋๋ค.
์ ํ ๋ค์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. HTTP API ์์ฒญ์ ์ํ @nuxt/axios ๋ @nuxt/http ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. ์ธ์ฆ header ์ค์ ์ ์ํ ๊ฐ์ด๋์ ๊ฐ์ ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ๋ํ ๋ ๋ง์ ์ ๋ณด๋ documentation๋ฅผ ์ฐพ์๋ณด์๊ธฐ ๋ฐ๋๋๋ค.
๋ง์ฝ
fetch๋asyncData๋ฅผ mixin ๋ด์ ์ ์ํ๊ณ page ์ปดํฌ๋ํธ์์๋ ์ ์ํ๋ ๊ฒฝ์ฐ, mixin ํจ์๋ ๋ฎ์ฌ์์ด์ง๋๋ค.
The fetch hook
Nuxt 2.12 ์ด์ ์ page ์ปดํฌ๋ํธ์์๋ง ๋์๋๊ณ ์ปดํฌ๋ํธ์์ ์ ๊ทผํ ์ ์๋
fetchํ ๊ณผ๋ ๋ค๋ฆ ๋๋ค. ๋ง์ฝfetch()๊ฐcontextargument๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ฉด, ๊ทธ๊ฒ์ ๋ ๊ฑฐ์ fetch ์ผ๋ก ์ทจ๊ธ๋ฉ๋๋ค. ์ด๊ฒ์ deprecated ๋์์ผ๋ฉฐasyncData๋๋ anonymouse middleware๋ก ๊ต์ฒดํ์ฌ์ผ ํฉ๋๋ค.
fetch๋ ์ปดํฌ๋ํธ๊ฐ ์์ฑ๋ ํ server-side ๋ ๋๋ง ๋์ client์์ ๋ถ๋ ค์ง๋๋ค. fetch ํ
์ promise(๋ช
์์ , ๋๋ async/await๋ฅผ ์ฌ์ฉํ ์์์ )๋ฅผ ๋ฐํํฉ๋๋ค.
- ์๋ฒ์์๋ ์ด๊ธฐ ํ์ด์ง ๋ ๋ ์
- ํด๋ผ์ด์ธํธ์์๋ ์ปดํฌ๋ํธ๊ฐ mounted ๋๊ณ ์ผ์ ์๊ฐ ๊ฒฝ๊ณผ
static hosting์์, fetch ํ ์ page ์์ฑ ์ค์๋ง ๋ถ๋ฆฝ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ฒฐ๊ณผ๋ ํด๋ผ์ด์ธํธ์์ ์ฌ์ฉํ ์ ์๋๋ก ์บ์ฑ๋ฉ๋๋ค. ์บ์ ์ถฉ๋์ ๋ฐฉ์งํ๋ ค๋ฉด ์ปดํฌ๋ํธ์ ์ด๋ฆ์ ์ง์ ํ๊ฑฐ๋ ๊ณ ์ ํ fetchKey๋ฅผ ์ ๊ณตํด์ผ ํฉ๋๋ค.
Usage
Fetching data
fetch ํ
๋ด์์๋ ์ปดํฌ๋ํธ์ this ๊ฐ์ฒด์ ์ ๊ทผํ ์ ์์ต๋๋ค.
๋ค๋ฅธ ์์ฑ์ ์์ ํ๋ ค๋ฉด
data()์์ ๋ฏธ๋ฆฌ ์ ์ธํด์ผ ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ fetch์์ ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ data์์ ์ ์ธํ ์์ฑ์ ํ ๋นํ ์ ์์ต๋๋ค.
Changing fetch behavior
fetchOnServer: Boolean ๋๋ Function (default: true) ํ์ด์ง๊ฐ server-rendering ๋ fetch๊ฐ ํธ์ถ๋ฉ๋๋ค.
fetchKey: String ๋๋ Function (์ปดํฌ๋ํธ scope ID ๋๋ ์ปดํฌ๋ํธ๋ช
์ด ๊ธฐ๋ณธ) ์ปดํฌ๋ํธ์ fetch ๊ฒฐ๊ณผ๋ฅผ ์๋ณํ ์ ์๋ key (๋๋ ๊ณ ์ ํค๋ฅผ ์์ฑํ๋ ํจ์) (Nuxt 2.15+ ์ฌ์ฉ ๊ฐ๋ฅ).
ํ์ด์ง๊ฐ server-rendered ๋ ๋ ์ด ํค๋ ์๋ฒ ์ธก ๊ฒฐ๊ณผ๋ฅผ fetch() ํด๋ผ์ด์ธํธ ์ธก ๊ตฌ์ฑ ์์ ๋ฐ์ดํฐ ์ ๋งคํํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์๋ณธ PR ์์ ๋ ๋ง์ ์ ๋ณด๋ฅผ ์ป์ ์ ์์ต๋๋ค.
fetchDelay: Integer (default: 200), ์ต์ ์คํ ์๊ฐ์ ์ด๋จ์๋ก ์ค์ ํ๋ค. (๋น ๋ฅธ ๊น๋นก์์ ํผํ๊ธฐ ์ํด)
fetchOnServer๋ ์ฐธ/๊ฑฐ์ง, fetch๋ clinet-side์์๋ง ํธ์ถํ ์ ์๊ณ , server-side ์ปดํฌ๋ํธ์์๋ $fetchState.pending๋ true๋ฅผ ๋ฐํํ๋ค.
export default {
data: () => ({
posts: []
}),
async fetch() {
this.posts = await this.$http.$get('https://api.nuxtjs.dev/posts')
},
fetchOnServer: false,
// multiple components can return the same `fetchKey` and Nuxt will track them both separately
fetchKey: 'site-sidebar',
// alternatively, for more control, a function can be passed with access to the component instance
// It will be called in `created` and must not depend on fetched data
fetchKey(getCounter) {
// getCounter is a method that can be called to get the next number in a sequence
// as part of generating a unique fetchKey.
return this.someOtherData + getCounter('sidebar')
}
}Accessing the fetch state
fetch ํ
์ ๋ค์๊ณผ ๊ฐ์ ํน์ฑ์ ๊ฐ์ง ์ปดํฌ๋ํธ์ ๋ ๋ฒจ์์ this.$fetchState์ ๋ํ๋
๋๋ค.
pending์ clinet-side ์์fetch๊ฐ ํธ์ถ๋์์ ๋Boolean๊ฐ์ ๋ํ๋ ๋๋ค.error๋fetchํ ์ผ๋ก๋ถํฐnull์ด๊ฑฐ๋Error๋ฅผ ๋ฐํํ ๊ฒฝ์ฐ์ ๋๋ค.timestamp๋ ๋ง์ง๋ง fetch๋ฅผ ๋ํ๋ด๋ ์๊ฐ์ ๋๋ค.keep-alive๋ฅผ ์ฌ์ฉํด ์บ์ฑํ๋๋ฐ ์ ์ฉํฉ๋๋ค.
์ถ๊ฐ๋ก Nuxt์์ ๋ถ๋ ค์ง๋ fetch ์ธ์๋, ์ปดํฌ๋ํธ ๋ด์์ this.$fetch()๋ฅผ ํตํด fetch๋ฅผ ํธ์ถํ ์ ์๋ค. (e.g. ๋น๋๊ธฐ ๋ฐ์ดํฐ๋ฅผ ๋ฆฌ๋ก๋)
<template>
<div>
<p v-if="$fetchState.pending">Fetching mountains...</p>
<p v-else-if="$fetchState.error">An error occurred :(</p>
<div v-else>
<h1>Nuxt Mountains</h1>
<ul>
<li v-for="mountain of mountains">{{ mountain.title }}</li>
</ul>
<button @click="$fetch">Refresh</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
mountains: []
}
},
async fetch() {
this.mountains = await fetch(
'https://api.nuxtjs.dev/mountains'
).then(res => res.json())
}
}
</script>fetch ํ ๋ง๊ณ ๋
this.$nuxt.context๋ฅผ ์ฌ์ฉํด Nuxt context ์ ์ ๊ทผํ ์ ์๋ค.
Listening to query string changes
fetch ํ
์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฟผ๋ฆฌ ์คํธ๋ง์ด ๋ณ๊ฒฝ๋์์ ๋ ํธ์ถ๋์ง ์๋๋ค. ์ฟผ๋ฆฌ ๋ณ๊ฒฝ์ ๊ฐ์ํ๋ ค๋ฉด $route.query๋ฅผ ์ถ๊ฐํด์ผํ๋ค.
export default {
watch: {
'$route.query': '$fetch'
},
async fetch() {
// Called also on query changes
}
}Caching
<nuxt />์ <nuxt-child />์ปดํฌ๋ํธ์ keep-alive ๋๋ ํฐ๋ธ๋ฅผ ์ฌ์ฉํด ์ด๋ฏธ ๋ฐฉ๋ฌธํ ํ์ด์ง์์ ํธ์ถํ fetch๋ฅผ ์ ์ฅํ ์ ์์ต๋๋ค.
<template>
<nuxt keep-alive />
</template>๋ํ <nuxt> ์ปดํฌ๋ํธ์ keep-alive-props ๋ฑ์ props ๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
<nuxt keep-alive :keep-alive-props="{ max: 10 }" />10๊ฐ์ ํ์ด์ง ์ปดํฌ๋ํธ๋ง ์ ์ฅ๋ฉ๋๋ค.
Error handling
๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์ค ์๋ฌ๊ฐ ๋ฐ์ํ๋ค๋ฉด ์ ์์ ์ธ Nuxt ์ค๋ฅ ํ์ด์ง๊ฐ ๋ก๋๋์ง ์์ต๋๋ค.
fetch()๋ด์ Nuxtredirect๋error๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ง ์๋ ๋์ ์ ์ปดํฌ๋ํธ ๋ด์์$fetchState.error๋ฅผ ์ฌ์ฉํด ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.
๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์ค error๊ฐ ์๋ค๋ฉด $fetchState.error๋ฅผ ํ์ธํด ์๋ฌ ๋ฉ์์ง๋ฅผ ๋ณผ ์ ์๋ค.
<template>
<div>
<p v-if="$fetchState.pending">Loading....</p>
<p v-else-if="$fetchState.error">Error while fetching mountains</p>
<ul v-else>
<li v-for="(mountain, index) in mountains" :key="index">
{{ mountain.title }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
mountains: []
}
},
async fetch() {
this.mountains = await fetch(
'https://api.nuxtjs.dev/mountains'
).then(res => res.json())
}
}
</script>Using activated hook
Nuxt๋ ๋ง์ง๋ง fetch ํธ์ถ(ssr ํฌํจ)์ this.$fetchState.timestamp์ ๋ด์๋๊ณ ์์ต๋๋ค.
activatedํ
์ด ํฌํจ๋ ์์ฑ์ ์ฌ์ฉํ์ฌ fetch์ 30์ด ์บ์๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค.
<template> ... </template>
<script>
export default {
data() {
return {
posts: []
}
},
activated() {
// Call fetch again if last fetch more than 30 sec ago
if (this.$fetchState.timestamp <= Date.now() - 30000) {
this.$fetch()
}
},
async fetch() {
this.posts = await fetch('https://api.nuxtjs.dev/posts').then(res =>
res.json()
)
}
}
</script>๋ง์ง๋ง fetch ํธ์ถ์ด 30์ด ์ ์ธ ๊ฒฝ์ฐ ๋์ผ ํ์ด์ง๋ก์ ํ์์ด ํธ์ถ๋์ง ์์ต๋๋ค.
Async Data
asyncData๋ pages์์๋ง ์ฌ์ฉํ ์ ์๊ณ ํ ๋ด์์this์ ์ ๊ทผํ ์ ์์ต๋๋ค.
asyncData๋ ๋ฒ์ฉ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํ ๋ค๋ฅธ ํ
์
๋๋ค. ๋น๋๊ธฐ ์ํ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ์์ฑ ์ ์๊ฐ ํ์ํ fetch์ ๋ฌ๋ฆฌ asyncData๋
์ปดํฌ๋ํธ์ ๋ก์ปฌ state์ ๋ฐํ ๊ฐ์ ๋ณํฉํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค. ์ฌ๊ธฐ @nuxt/http ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์์ ๊ฐ ์์ต๋๋ค.
<template>
<div>
<h1>{{ post.title }}</h1>
<p>{{ post.description }}</p>
</div>
</template>
<script>
export default {
async asyncData({ params, $http }) {
const post = await $http.$get(`https://api.nuxtjs.dev/posts/${params.id}`)
return { post }
}
}
</script>fetch์ ๋ฌ๋ฆฌ asyncData ํ
์ผ๋ก ๋ฆฌํด๋ promise๋ route ์ ํ ์ค์ ํด๊ฒฐ๋ฉ๋๋ค. ์ด๊ฒ์ client-side ์ ํ ์ค์๋ โloading placeholderโ๊ฐ ํ์๋์ง ์๋๋ค๋๊ฑธ ์๋ฏธํฉ๋๋ค.
(loading bar๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์์๊ฒ ๋ก๋ ์ํ๋ฅผ ๋ํ๋ผ ์ ์์).
๋์ Nuxt๋ ๋ค์ ํ์ด์ง๋ ์๋ฌ ํ์ด์ง๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ ์ ์ asyncData ํ
์ด ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค.
์ด ํ
์ page-level ์ปดํฌ๋ํธ์์๋ง ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค. fetch์๋ ๋ค๋ฅด๊ฒ asyncData๋ ์ปดํฌ๋ํธ์ this์ ์ ๊ทผํ ์ ์์ต๋๋ค.
๋์ , argument๋ก the context ๋ฅผ ๋ฐ์ต๋๋ค. ์ด๊ฒ์ ์ฌ์ฉํด ๋ช๋ช์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๊ณ Nuxt๋ ์๋์ผ๋ก
์ปดํฌ๋ํธ์ ๋ฐ์ดํฐ์ ๋ฆฌํด ๊ฐ์ฒด๋ฅผ ๋ณํฉํ ์ ์์ต๋๋ค.
๋ค์ ์์๋, API๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ๋ ๊ถ์ฅํ๋ @nuxt/http ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
Async data in components?
์ปดํฌ๋ํธ๋ asyncData๋ฅผ ๊ฐ๊ณ ์์ง ์๊ธฐ ๋๋ฌธ์ ์ปดํฌ๋ํธ ๋ด์์ ์ง์ server-side ๋น๋๊ธฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
์ ํ์ ๊ทน๋ณตํ๊ธฐ ์ํด 3๊ฐ์ง ์ต์
์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- Nuxt 2.12 ์ดํ ๋ฒ์ ์์๋ถํฐ ์ฌ์ฉ ๊ฐ๋ฅํ ์๋ก์ด
fetchhook ์ ์ฌ์ฉํฉ๋๋ค. mountedํ ์์์ API ํธ์ถ์ ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ loaded ์์ ์ data ์์ฑ์ ์ง์ ํฉ๋๋ค. ๋จ์ : server side rendering ์์๋ ์๋ํ์ง ์์ต๋๋ค.- page ์ปดํฌ๋ํธ์
asyncData์์์ API๋ฅผ ํธ์ถํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ํ์ ์ปดํฌ๋ํธ๋ก data๋ฅผ props๋ก ์ ๋ฌํฉ๋๋ค. Server rendering์ ์ ๋์ํฉ๋๋ค.
๋จ์ : ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ฉํ๊ธฐ ์ํด page์ asyncData๋ ๊ฐ๋
์ฑ์ด ๋จ์ด์ง ์ ์์ต๋๋ค.
Listening to query changes
๊ธฐ๋ณธ์ ์ผ๋ก asyncData๋ query string ๋ณ๊ฒฝ์ ์ํด ํธ์ถ๋์ง ์์ต๋๋ค. page ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ ๋์ฒ๋ผ ๋์์ ๋ณ๊ฒฝํ๋ ค๋ฉด page ์ปดํฌ๋ํธ์
watchQuery ์์ฑ์ผ๋ก ๋ฐ๋ ํ๋ผ๋ฏธํฐ๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค.