iBetter Books
수정

Ch 01. useFetch와 useAsyncData

Nuxt 3에서 데이터를 가져오는 방법은 크게 두 가지입니다. useFetchuseAsyncData입니다. 둘 다 서버와 클라이언트 양쪽에서 안전하게 동작하고, SSR 과정에서 중복 요청을 방지해 줍니다. 차이점은 "얼마나 직접 제어하고 싶은가"에 달려 있습니다.

useFetch — URL 한 줄로 끝내기

useFetch는 URL을 넘기면 나머지를 Nuxt가 처리해 주는 단축어입니다. 내부적으로 useAsyncData + $fetch의 조합으로 구현되어 있습니다.

// pages/posts/index.vueconst { data: posts, pending, error, refresh } = await useFetch('/api/posts')

반환값은 다음 네 가지입니다.

  • data — 응답 데이터 (Ref)
  • pending — 로딩 여부 (Ref<boolean>)
  • error — 오류 객체 (Ref)
  • refresh / execute — 수동 재요청 함수

TypeScript를 사용한다면 제네릭으로 응답 타입을 명시할 수 있습니다.

interface Post {  id: number  title: string  body: string}const { data } = await useFetch<Post[]>('/api/posts')// data.value는 Post[] | null 타입으로 추론됩니다

useAsyncData — 비동기 로직을 직접 감싸기

URL이 아니라 커스텀 비동기 로직이 필요할 때는 useAsyncData를 사용합니다. 첫 번째 인자는 캐시 키, 두 번째 인자는 비동기 함수입니다.

// pages/users/[id].vueconst route = useRoute()const { data: user } = await useAsyncData('user-detail', async () => {  const res = await $fetch(`/api/users/${route.params.id}`)  return res})

같은 캐시 키를 가진 요청은 SSR 과정에서 한 번만 실행되고 결과가 클라이언트로 전달됩니다.

주요 옵션

두 함수 모두 세 번째 인자(또는 두 번째)로 옵션 객체를 받습니다.

옵션 설명
lazy: true SSR을 건너뛰고 클라이언트에서 로드합니다. pending이 true인 동안 스켈레톤을 보여줄 때 유용합니다.
server: false 서버에서 실행하지 않습니다. 브라우저 전용 API를 사용할 때 씁니다.
transform 응답 데이터를 가공한 뒤 저장합니다.
pick 응답에서 필요한 필드만 추출합니다. 전송 크기를 줄여 줍니다.
const { data } = await useFetch('/api/articles', {  transform: (res) => res.articles,  pick: ['id', 'title', 'publishedAt']})

refresh와 execute로 수동 재요청하기

refresh()는 기존 캐시를 무효화하고 즉시 재요청합니다. execute()는 최초 호출 전까지 실행을 미루고 싶을 때 immediate: false 옵션과 함께 씁니다.

const { data, refresh } = await useFetch('/api/notifications')// 버튼 클릭 시 재요청function onClickRefresh() {  refresh()}

useFetch는 단순하고 useAsyncData는 유연합니다. URL 하나로 충분하다면 useFetch를, 여러 API를 조합하거나 로직이 복잡하다면 useAsyncData를 선택하면 됩니다.