들어가며
회사 홈페이지 리팩토링 작업에서 Vue.js 기반의 환경은 SEO(Search Engine Optimization)가 취약하여 이를 보완하기 위해 NuxtJS 프레임워크를 이용했습니다. NuxtJS에서 학습하면서 알게 된 Data Fetching의 asyncData와 fetch의 차이를 이야기하고자 합니다.
Vue.js에서 Data Fetching 하는 법
기존 Vue.js에서는 Lifecycle이 동기적으로 진행되기 때문에 mounted() Lifecycle 훅에서 비동기 구문을 이용해서 API 데이터를 호출해줘야 합니다.
import axios from 'axios';
export default {
data() {
productList: [],
},
mounted() {
this.getProductList();
},
methods: {
async getProductList() {
const res = await axios.get('/product');
this.productList = res.data;
},
},
};
비동기 구문이란?
async/await, Promise, 콜백 함수를 이용하여 서버에 데이터를 요청할 동안 병렬적으로 다른 동작을 수행하고 응답이 왔을 때 화면에 출력하도록 해주는 구문입니다. 동기 / 비동기에 대해 알고 싶으신 분들은 비동기 이해하기 #1을 읽어주세요.
NuxtJS에서 Data Fetching 하는 법
NuxtJS에서는 서버 사이드 렌더링 동안 비동기 처리로 데이터를 가져올 수 있는 asyncData와 fetch 훅이 있습니다. NuxtJS의 Lifecycle 훅의 asyncData, fetch의 위치는 다음 이미지와 같습니다.
asyncData
- created() 훅의 직전에 실행되어 vue가 렌더링이 안 된 상태라 this 컨텍스트 사용이 어렵습니다.
- 페이지 컴포넌트(pages 폴더 내 컴포넌트)에서만 사용할 수 있으며 페이지 컴포넌트의 data에 값이 초기화됩니다. (this 사용이 안 되므로 data는 return {}으로 반환합니다.)
- 클라이언트 렌더링 중 로딩이 표시되지 않아 에러가 발생할 시 리다이렉트를 실행할 수 있습니다.
- context를 parameter로 넘길 수 있습니다.
context의 종류
- app, store, route, params, query, env, isDev, isHMR, redirect, error, $config
// asyncData 훅을 사용하여 productList 데이터값을 초기화하기
<template>
<div>
<ul>
<li v-for="item of productList">{{ item.name }}</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
productList: [],
},
async asyncData() {
const { data } = await axios.get('/product');
const productList = data;
return { productList }
},
async asyncData({ redirect }) {
return await axios.get('/product');
}
};
</script>
fetch
- created() 훅의 이후 실행되어 this 컨텍스트 사용이 가능합니다.
- 페이지 컴포넌트를 포함한 모든 컴포넌트(components 폴더 내 컴포넌트)에 사용할 수 있습니다.
- 에러가 발생할 시 에러 콘텐츠를 구성할 수 있습니다. ($fetchState 이용)
- 라이프사이클 이외 수동으로 여러 번 호출이 가능합니다. ($fetch 이용)
- parameter를 넘길 수 없습니다.(v2.12이후 deprecated)
- Vuex의 store 데이터를 사용할 수 있습니다.
fetch 속성, 옵션 및 관련 디렉티브
- fetchOnServer(Options) : 서버사이드 렌더링 중 fetch()를 실행할 지를 결정 (기본값: true)
- fetchDelay(Options) : 최소 실행시간(기본값 : 200ms)
- keep-alive(Directive) : (혹은 ) 추가 시 fetch()이 캐싱돼서 이미 방문한 페이지는 api를 호출하지 않음.
// fetch 훅 속성 중 $fetch, $fetchState 이용하여 화면 노출하기
<template>
<div>
<ul v-if="$fetchState.pending && productList.length > 0">
<li v-for="item of productList">{{ item.name }}</li>
</ul>
<p v-else-if="$fetchState.error">일시적인 장애로 리스트를 불러올 수 없습니다.</p>
<p v-else>리스트가 없습니다.</p>
<button @click="clickRefresh">리스트 다시 불러오기</button>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
productList: [],
},
async fetch() {
const { data } = await axios.get('/product');
this.productList = data;
},
method: {
clickRefresh() {
this.$fetch();
},
}
};
</script>
// fetch훅에서 Vuex store 사용하기
<template>
<div>
<ul v-if="$store.productList.length > 0">
<li v-for="item of $store.productList">{{ item.name }}</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
export default {
async fetch() {
await this.$store.dispatch('GET_PRODUCT_LIST');
},
};
</script>
마치며
NuxtJS를 10월에 1~2일 만에 짧은 시간동안 수박 겉핥기로 읽어 봤는데 이번에 블로그를 작성하느라 공식 문서를 확인하면서 코드로 쳐보니 그 둘의 차이점도 다시 알 수 있었습니다. 아직 NuxtJS를 프로젝트를 통해 작업해보지 않았지만 Vue.js와의 구현 방식의 차이, 특징들을 제대로 이해하며 공부해야겠습니다.
감사합니다.
참고문서