dev.syw

useFetch·useAsyncData·$fetch의 차이와 옵션, 에러·로딩 처리.

데이터 패칭

서버에서 데이터를 받아오는 일은 거의 모든 앱의 핵심입니다. Nuxt는 SSR과 클라이언트를 모두 고려한 데이터 패칭 도구를 제공합니다. 이번 레슨에서는 useFetch, useAsyncData, $fetch 의 차이와 주요 옵션, 그리고 로딩·에러 상태 처리를 다룹니다.

학습 목표

  • useFetch, useAsyncData, $fetch 를 언제 쓰는지 구분한다.
  • lazy, server, key 같은 옵션의 의미를 이해한다.
  • 데이터를 다시 불러오는 방법을 안다.
  • pending, error 로 로딩·에러 상태를 처리한다.

세 가지 도구 비교

도구용도SSR 중복 방지
useFetch컴포넌트에서 URL로 데이터 받기O
useAsyncData임의의 비동기 로직 결과를 받기O
$fetch이벤트 핸들러 등에서 단발 요청X

핵심은 useFetch / useAsyncData 는 SSR에서 받은 데이터를 클라이언트로 전달 해 재요청을 막는다는 점입니다. $fetch 는 그런 처리가 없는 순수 요청 함수입니다.

useFetch

가장 자주 쓰는 도구입니다. URL을 넘기면 데이터·로딩·에러를 한 번에 돌려줍니다.

<script setup>
const { data, pending, error, refresh } = await useFetch('/api/tasks');
</script>

<template>
  <p v-if="pending">불러오는 중...</p>
  <p v-else-if="error">에러: {{ error.message }}</p>
  <ul v-else>
    <li v-for="t in data" :key="t.id">{{ t.title }}</li>
  </ul>
</template>

useAsyncData

URL이 아니라 임의의 비동기 함수 결과를 SSR 친화적으로 다루고 싶을 때 씁니다. 첫 인자는 캐시 키, 둘째는 함수입니다.

const { data } = await useAsyncData('tasks', () => $fetch('/api/tasks'));

// 여러 호출을 조합할 수도 있다
const { data: dashboard } = await useAsyncData('dashboard', async () => {
  const [tasks, users] = await Promise.all([
    $fetch('/api/tasks'),
    $fetch('/api/users'),
  ]);
  return { tasks, users };
});

💡 TIPuseFetch(url) 는 사실상 useAsyncData(key, () => $fetch(url)) 의 편의 버전입니다. URL만 있으면 useFetch, 로직이 복잡하면 useAsyncData 를 고르세요.

$fetch

버튼 클릭, 폼 전송처럼 사용자 동작에 반응하는 단발 요청 에는 $fetch 를 씁니다. 컴포넌트 최상단이 아니라 핸들러 안에서 호출합니다.

async function addTask(title: string) {
  await $fetch('/api/tasks', {
    method: 'POST',
    body: { title },
  });
}

⚠️ 주의 — 컴포넌트 셋업 단계의 데이터 로딩에 $fetch 만 쓰면 SSR과 클라이언트에서 두 번 요청 될 수 있습니다. 이럴 때는 useFetch / useAsyncData 를 쓰세요.

주요 옵션

const { data, status } = await useFetch('/api/tasks', {
  lazy: true,        // 네비게이션을 막지 않고 백그라운드로 로딩
  server: false,     // 서버에서 받지 않고 클라이언트에서만 요청
  key: 'tasks',      // 캐시 키를 직접 지정
  query: { page: 1 },// 쿼리스트링
  default: () => [], // 로딩 전 기본값
});
옵션효과
lazy페이지 전환을 막지 않고 비동기로 로딩 (스켈레톤 UI에 적합)
serverfalse 면 SSR을 건너뛰고 클라이언트에서만 요청
key캐시 식별자. 같은 키는 데이터를 공유
query / params쿼리스트링·경로 파라미터
default데이터가 도착하기 전의 기본값

리패칭 (다시 불러오기)

refresh() 를 호출하면 같은 요청을 다시 보냅니다. 반응형 파라미터를 watch 로 묶어 자동 갱신할 수도 있습니다.

<script setup>
const page = ref(1);

// page 가 바뀌면 자동으로 다시 요청
const { data, refresh } = await useFetch('/api/tasks', {
  query: { page },
  watch: [page],
});
</script>

<template>
  <button @click="refresh()">새로고침</button>
  <button @click="page++">다음 페이지</button>
</template>

에러와 로딩 처리

useFetch 가 돌려주는 pending(또는 status)과 error 로 화면 상태를 분기합니다.

<script setup>
const { data, status, error } = await useFetch('/api/tasks');
// status: 'idle' | 'pending' | 'success' | 'error'
</script>

<template>
  <Loading v-if="status === 'pending'" />
  <ErrorBox v-else-if="error" :message="error.message" />
  <TaskList v-else :items="data" />
</template>

요약

  • useFetch / useAsyncData 는 SSR 데이터를 클라이언트로 전달해 중복 요청을 막습니다.
  • URL만 있으면 useFetch, 복잡한 로직이면 useAsyncData 를 씁니다.
  • 사용자 동작에 반응하는 단발 요청은 $fetch 가 적합합니다.
  • lazy, server, key, watch 옵션으로 동작을 세밀하게 제어합니다.

연습문제

  1. useFetch('/api/tasks') 로 일감 목록을 받아 pending·error·정상 상태를 모두 화면에 표현해 보세요.
  2. page ref와 watch 옵션을 묶어, 페이지 버튼을 누르면 데이터가 자동 갱신되게 만들어 보세요.
  3. 폼 제출 시 $fetch 로 새 일감을 POST하고, 성공하면 refresh() 로 목록을 갱신해 보세요.
  4. lazy: trueserver: false 를 적용했을 때 화면 동작이 어떻게 달라지는지 비교해 보세요.

힌트 — 셋업 단계 로딩은 useFetch, 핸들러 안 요청은 $fetch 라는 규칙을 떠올리세요.

💡 연습문제 풀이

불러오는 중…

함께 보면 좋은 자료

댓글 0

Nuxt.js” 강좌에 대한 댓글입니다.

댓글을 작성하려면 로그인이 필요합니다.