Nuxt Data fetching

asyncData와 fetch의 차이


들어가며

회사 홈페이지 리팩토링 작업에서 Vue.js 기반의 환경은 SEO(Search Engine Optimization)가 취약하여 이를 보완하기 위해 NuxtJS 프레임워크를 이용했습니다. NuxtJS에서 학습하면서 알게 된 Data Fetching의 asyncDatafetch의 차이를 이야기하고자 합니다.

Vue.js에서 Data Fetching 하는 법

기존 Vue.js에서는 라이프사이클이 동기적으로 진행되기 때문에 mounted() 라이프사이클 훅에서 비동기 구문을 이용해서 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에서는 서버 사이드 렌더링 동안 비동기 처리로 데이터를 가져올 수 있는 asyncDatafetch 훅이 있습니다. NuxtJS의 Lifecyle 훅의 asyncData, fetch의 위치는 다음 이미지와 같습니다.

nuxtServerInit → RouteMiddleware → validate → asyncData → created → fetch → mounted → rest of the Vue Lifecycle Hooks
NuxtJS Lifecycle Hooks

 asyncData

  1. created() 훅의 직전에 실행되어 vue가 렌더링이 안 된 상태라 this 컨텍스트 사용이 어렵습니다.
  2. 페이지 컴포넌트(pages 폴더 내 컴포넌트)에서만 사용할 수 있으며 페이지 컴포넌트의 data에 값이 초기화됩니다. (this 사용이 안되므로 data는 return {} 으로 반환합니다.)
  3. 클라이언트 렌더링 중 로딩이 표시되지 않아 에러가 발생할 시 리다이렉트를 실행할 수 있습니다.
  4. 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

  1. created() 훅의 이후 실행되어 this 컨텍스트 사용이 가능합니다.
  2. 페이지 컴포넌트를 포함한 모든 컴포넌트(components 폴더 내 컴포넌트)에 사용할 수 있습니다.
  3. 에러가 발생할 시 에러 콘텐츠를 구성할 수 있습니다.($fetchState 이용)
  4. 라이프사이클 이외 수동으로 여러 번 호출이 가능합니다.($fetch 이용)
  5. parameter를 넘길 수 없습니다.(v2.12이후 deprecated)
  6. 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와의 구현방식의 차이, 특징들을 제대로 이해하며 공부해야겠습니다.

감사합니다.

 참고문서