2. useAsyncData

데이터 통신과 관련한 거의 모든 내용은 "Nuxt-개요 > 데이터 가져오기" 에 담겨있다.

이번 장에서 간단하게 실습한 후 위 내용을 참고하면 이해에 더 도움이 될 것이다.

 

useFetch 컴포저블을 사용하는 것이 적절하지 않은 경우가 있다 (예: CMS 또는 자체적으로 API 통신 레이어를 제공해야 하는 경우). 이 경우 useAsyncData 를 사용하여 호출을 래핑하면서도 컴포저블에서 제공하는 이점을 계속 유지할 수 있다.

 

앞 장에서 useFetch 컴포저블을 이용한 todos 의 예를 useAsyncData 로 바꿔보자. 데이터를 캐싱하는데 필요한 문자열 키가 필요하다. 키가 주어지지 않으면 파일명과 해당 소스라인으로 자동으로 구성된 키가 할당된다.

 

/pages/todos.vue

<script setup lang="ts">
// const { data: todos, pending, error, refresh } = await useFetch('https://jsonplaceholder.typicode.com/todos', { method:'get', server: false })

const { data: todos, error, refresh } = await useAsyncData("todos", () =>
  $fetch('https://jsonplaceholder.typicode.com/todos', { method:'get' })
)
</script>

<template>
<div>
  <table class="min-w-full table-auto bg-blue-950">
    <thead>
    <tr>
      <th class="px-4 py-2">ID</th>
      <th class="px-4 py-2">Title</th>
      <th class="px-4 py-2">Completed</th>
    </tr>
    </thead>
    <tbody>
    <!-- Loop through todosData to populate the table rows -->
    <tr v-for="todo in todos">
      <td class="border px-4 py-2">{{ todo.id }}</td>
      <td class="border px-4 py-2">{{ todo.title }}</td>
      <td class="border px-4 py-2">
        <!-- Use a checkmark if completed, otherwise a cross -->
        <span :class="{ 'text-green-500': todo.completed, 'text-red-500': !todo.completed }">
                            {{ todo.completed ? '✔' : '❌' }}
                        </span>
      </td>
    </tr>
    </tbody>
  </table>
</div>
</template>

<style scoped>

</style>

브라우저 소스보기를 보면 결과는 useFetch 를 사용한 것과 동일한 것을 알 수 있다.

 

클라이언트 측 렌더링도 살펴보자.

 

/pages/todos.vue

<script setup lang="ts">
// const { data: todos, pending, error, refresh } = await useFetch('https://jsonplaceholder.typicode.com/todos', { method:'get', server: false })

const { data: todos, error, refresh } = await useAsyncData("todos", () =>
  $fetch('https://jsonplaceholder.typicode.com/todos', { method:'get'}), {server: false}
)
</script>
...

브라우저 소스보기 결과는 아래와 같다.

 

브라우저 개발자도구를 보면 클라이언트 측에서 호출되는 것을 확인할 수 있다.

 

위에서 본 것처럼 useAyncData("key", $fetch(url)) 은 useFetch 와 거의 동일하다.

 

자신만의 데이터 통신 컴포저블을 만들때는 useAsyncData를 통해서 구현할 수 있음을 알 수 있다.

Promise.all 을 이용해 동시에 데이터를 가져와서 변수에 할당 할 수도 있다.

 

/pages/todos-users.vue

<script setup lang="ts">
// const { data: todos, pending, error, refresh } = await useFetch('https://jsonplaceholder.typicode.com/todos', { method:'get', server: false })

// const { data: todos, error, refresh } = await useAsyncData("todos", () =>
//   $fetch('https://jsonplaceholder.typicode.com/todos', { method:'get'}), {server: false}
// )
//https://jsonplaceholder.typicode.com/users
const { data, pending } = await useAsyncData('todos-users', async () => {
  const [todos, users] = await Promise.all(
      [$fetch('https://jsonplaceholder.typicode.com/todos', { method:'get'}),
        $fetch('https://jsonplaceholder.typicode.com/users', { method:'get'})
  ])

  return {
    todos,
    users
  }
})
</script>

<template>
<div>
  <table class="min-w-full table-auto bg-blue-950">
    <thead>
    <tr>
      <th class="px-4 py-2">ID</th>
      <th class="px-4 py-2">Title</th>
      <th class="px-4 py-2">Completed</th>
    </tr>
    </thead>
    <tbody>
    <!-- Loop through todosData to populate the table rows -->
    <tr v-for="todo in data.todos">
      <td class="border px-4 py-2">{{ todo.id }}</td>
      <td class="border px-4 py-2">{{ todo.title }}</td>
      <td class="border px-4 py-2">
        <!-- Use a checkmark if completed, otherwise a cross -->
        <span :class="{ 'text-green-500': todo.completed, 'text-red-500': !todo.completed }">
                            {{ todo.completed ? '✔' : '❌' }}
                        </span>
      </td>
    </tr>
    </tbody>
  </table>
  <table class="min-w-full table-auto bg-green-950">
    <thead>
    <tr>
      <th class="px-4 py-2">ID</th>
      <th class="px-4 py-2">Name</th>
      <th class="px-4 py-2">Email</th>
    </tr>
    </thead>
    <tbody>
    <!-- Loop through todosData to populate the table rows -->
    <tr v-for="user in data.users">
      <td class="border px-4 py-2">{{ user.id }}</td>
      <td class="border px-4 py-2">{{ user.name }}</td>
      <td class="border px-4 py-2">{{ user.email }}</td>
    </tr>
    </tbody>
  </table>
</div>
</template>

<style scoped>

</style>

아래와 같이 동시 호출 후 변수 할당이 동작하는 것을 확인할 수 있다.

 

실습을 통해서 useAsyncData를 통해서 useFetch 의 기능을 대신하거나, 더 확장할 수 있음을 확인했다. 이 외 useLazyFetch, useLazyAsyncData 는 기본 컴포저블에 lazy 옵션만 추가하여 별도의 컴포저블로 정의한 컴포저블이다.

 

$fetch 는 unjs 의 ofetch 를 Nuxt 에 내장한 유틸리티 함수이다. ofetch 는 순수 자바스크립트 fetch 함수를 확장한 라이브러리 이다. 주요 특징은 다음과 같다.

  • 파싱응답
  • JSON Body
  • 오류처리 : await ofetch("url").catch(err);
  • 자동 재시도
  • 타임아웃관리
  • 제네릭 지원 : await<Await> ofetch("url");
  • baseURL지원 : await ofetch("url", { baseURL});
  • 쿼리검색 매개변수 지원
  • 인터셉터

 

자신만의 통신 함수 혹은 모듈을 만든다면 ofetch 를 시작점으로 하는 것도 좋은 방법인 것 같다. 예를 들어 파일 업로드/다운로드 기능을 시각적 요소를 갖고 있는 별도의 커스텀 컴포넌트로 만든다면 컴포넌트에 내장된 통신 함수는 ofetch 로 하면 좋을 것이다.

'Nuxt 개발 가이드 > 04. Data fetching' 카테고리의 다른 글

3. 풀스택을 위한 API 서버 구축  (0) 2024.01.14
1. useFetch  (0) 2024.01.13
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유