데이터 가져오기
Nuxt는 애플리케이션 내에서 데이터 가져오기를 처리하기 위한 composables를 제공합니다.
Nuxt는 브라우저 또는 서버 환경에서 데이터 가져오기를 수행하기 위한 두 가지 composables와 내장 라이브러리를 제공합니다: useFetch
, useAsyncData
및 $fetch
.
간단히 말해서:
$fetch
는 네트워크 요청을 수행하는 가장 간단한 방법입니다.useFetch
는 유니버설 렌더링에서 데이터를 한 번만 가져오는$fetch
의 래퍼입니다.useAsyncData
는useFetch
와 유사하지만 더 세밀한 제어를 제공합니다.
useFetch
와 useAsyncData
는 공통의 옵션과 패턴을 공유하며, 마지막 섹션에서 자세히 설명할 것입니다.
useFetch
와 useAsyncData
의 필요성
Nuxt는 서버와 클라이언트 환경 모두에서 동작할 수 있는 이소모픽(또는 유니버설) 코드를 실행할 수 있는 프레임워크입니다. Vue 컴포넌트의 setup 함수에서 $fetch
함수를 사용하여 데이터를 가져오면, 서버에서 한 번(HTML을 렌더링하기 위해)과 클라이언트에서 한 번(HTML이 하이드레이션될 때) 두 번 데이터를 가져오게 될 수 있습니다. 이는 하이드레이션 문제를 일으키고, 상호작용 시간을 증가시키며 예측할 수 없는 동작을 초래할 수 있습니다.
useFetch
와 useAsyncData
composables는 서버에서 API 호출이 이루어질 경우, 데이터를 페이로드로 클라이언트에 전달하여 이 문제를 해결합니다.
페이로드는 useNuxtApp().payload
를 통해 접근할 수 있는 JavaScript 객체입니다. 이는 하이드레이션 동안 브라우저에서 코드가 실행될 때 동일한 데이터를 다시 가져오는 것을 방지하기 위해 클라이언트에서 사용됩니다.
이 데이터를 Payload 탭에서 검사하려면 Nuxt DevTools를 사용하세요.
<script setup lang="ts">
const { data } = await useFetch('/api/data')
async function handleFormSubmit() {
const res = await $fetch('/api/submit', {
method: 'POST',
body: {
// 내 폼 데이터
}
})
}
</script>
<template>
<div v-if="data == null">
데이터 없음
</div>
<div v-else>
<form @submit="handleFormSubmit">
<!-- 폼 입력 태그 -->
</form>
</div>
</template>
위의 예에서 useFetch
는 요청이 서버에서 발생하고 브라우저로 적절히 전달되도록 보장합니다. $fetch
는 이러한 메커니즘이 없으며, 요청이 브라우저에서만 수행될 때 사용하는 것이 더 좋습니다.
Suspense
Nuxt는 Vue의 <Suspense>
컴포넌트를 사용하여 모든 비동기 데이터가 뷰에 제공되기 전에 탐색을 방지합니다. 데이터 가져오기 composables는 이 기능을 활용하여 호출별로 가장 적합한 것을 사용할 수 있도록 도와줍니다.
페이지 탐색 간에 진행 바를 추가하려면 <NuxtLoadingIndicator>
를 추가할 수 있습니다.
$fetch
Nuxt는 ofetch 라이브러리를 포함하고 있으며, 애플리케이션 전역에서 $fetch
별칭으로 자동으로 가져옵니다.
async function addTodo() {
const todo = await $fetch('/api/todos', {
method: 'POST',
body: {
// 내 할 일 데이터
}
})
}
$fetch
만 사용하면 네트워크 호출 중복 제거 및 탐색 방지를 제공하지 않습니다. :br
초기 컴포넌트 데이터를 가져올 때는 $fetch
를 클라이언트 측 상호작용(이벤트 기반)이나 useAsyncData
와 결합하여 사용하는 것이 좋습니다.
클라이언트 헤더를 API에 전달하기
서버에서 useFetch
를 호출할 때, Nuxt는 useRequestFetch
를 사용하여 클라이언트 헤더와 쿠키를 프록시합니다(전달되지 않아야 하는 헤더는 제외, 예: host
).
const { data } = await useFetch('/api/echo');
// /api/echo.ts
export default defineEventHandler(event => parseCookies(event))
대안으로, 아래 예는 서버 측 요청(클라이언트에서 시작된)에서 쿠키를 API에 접근하고 전송하기 위해 useRequestHeaders
를 사용하는 방법을 보여줍니다. 이소모픽 $fetch
호출을 사용하여 API 엔드포인트가 사용자의 브라우저에서 원래 전송된 동일한 cookie
헤더에 접근할 수 있도록 보장합니다. useFetch
를 사용하지 않는 경우에만 필요합니다.
const headers = useRequestHeaders(['cookie'])
async function getCurrentUser() {
return await $fetch('/api/me', { headers })
}
헤더를 자동으로 호출에 프록시하려면 useRequestFetch
를 사용할 수도 있습니다.
외부 API에 헤더를 프록시하기 전에 매우 주의하고 필요한 헤더만 포함하세요. 모든 헤더가 안전하게 우회될 수 있는 것은 아니며 원치 않는 동작을 초래할 수 있습니다. 프록시되지 말아야 할 일반적인 헤더 목록은 다음과 같습니다:
host
,accept
content-length
,content-md5
,content-type
x-forwarded-host
,x-forwarded-port
,x-forwarded-proto
cf-connecting-ip
,cf-ray
useFetch
useFetch
composable은 setup 함수에서 SSR 안전한 네트워크 호출을 수행하기 위해 $fetch
를 내부적으로 사용합니다.
<script setup lang="ts">
const { data: count } = await useFetch('/api/count')
</script>
<template>
<p>페이지 방문 수: {{ count }}</p>
</template>
이 composable은 useAsyncData
composable과 $fetch
유틸리티의 래퍼입니다.
useAsyncData
useAsyncData
composable은 비동기 로직을 래핑하고 해결되면 결과를 반환하는 역할을 합니다.
useFetch(url)
은 거의 useAsyncData(url, () => event.$fetch(url))
와 동일합니다. :br
가장 일반적인 사용 사례를 위한 개발자 경험 설탕입니다. (event.fetch
에 대해 더 알고 싶다면 useRequestFetch
를 참조하세요.)
useFetch
composable을 사용하는 것이 적절하지 않은 경우가 있습니다. 예를 들어, CMS나 타사에서 자체 쿼리 레이어를 제공하는 경우입니다. 이 경우, useAsyncData
를 사용하여 호출을 래핑하고 composable이 제공하는 이점을 계속 유지할 수 있습니다.
const { data, error } = await useAsyncData('users', () => myGetFunction('users'))
// 이것도 가능합니다:
const { data, error } = await useAsyncData(() => myGetFunction('users'))
useAsyncData
의 첫 번째 인수는 두 번째 인수인 쿼리 함수의 응답을 캐시하는 데 사용되는 고유 키입니다. 쿼리 함수를 직접 전달하여 이 키를 무시할 수 있으며, 키는 자동으로 생성됩니다.
:br :br
자동 생성된 키는 useAsyncData
가 호출된 파일과 줄만 고려하므로, 원치 않는 동작을 피하기 위해 항상 고유한 키를 생성하는 것이 좋습니다. 예를 들어, useAsyncData
를 래핑하는 사용자 정의 composable을 생성할 때입니다.
:br :br
키를 설정하면 useNuxtData
를 사용하여 구성 요소 간에 동일한 데이터를 공유하거나 특정 데이터를 새로 고침하는 데 유용할 수 있습니다.
const { id } = useRoute().params
const { data, error } = await useAsyncData(`user:${id}`, () => {
return myGetFunction('users', { id })
})
useAsyncData
composable은 여러 $fetch
요청이 완료될 때까지 래핑하고 기다린 다음 결과를 처리하는 훌륭한 방법입니다.
const { data: discounts, status } = await useAsyncData('cart-discount', async () => {
const [coupons, offers] = await Promise.all([
$fetch('/cart/coupons'),
$fetch('/cart/offers')
])
return { coupons, offers }
})
// discounts.value.coupons
// discounts.value.offers
useAsyncData
는 데이터를 가져오고 캐시하는 데 사용되며, Pinia 액션 호출과 같은 부작용을 트리거하는 데 사용되지 않습니다. 이는 nullish 값으로 반복 실행되는 등의 의도치 않은 동작을 초래할 수 있습니다. 부작용을 트리거해야 하는 경우, callOnce
유틸리티를 사용하세요.
const offersStore = useOffersStore()
// 이렇게 하면 안 됩니다
await useAsyncData(() => offersStore.getOffer(route.params.slug))
반환 값
useFetch
와 useAsyncData
는 아래에 나열된 동일한 반환 값을 가집니다.
data
: 전달된 비동기 함수의 결과입니다.refresh
/execute
:handler
함수에 의해 반환된 데이터를 새로 고치는 데 사용할 수 있는 함수입니다.clear
:data
를undefined
(또는 제공된 경우options.default()
의 값)로 설정하고,error
를null
로 설정하고,status
를idle
로 설정하며, 현재 보류 중인 요청을 취소된 것으로 표시하는 데 사용할 수 있는 함수입니다.error
: 데이터 가져오기가 실패한 경우의 오류 객체입니다.status
: 데이터 요청의 상태를 나타내는 문자열입니다("idle"
,"pending"
,"success"
,"error"
).
data
, error
및 status
는 <script setup>
에서 .value
로 접근할 수 있는 Vue refs입니다.
기본적으로 Nuxt는 refresh
가 완료될 때까지 기다린 후 다시 실행할 수 있습니다.
서버에서 데이터를 가져오지 않은 경우(예: server: false
), 데이터는 하이드레이션이 완료될 때까지 가져오지 않습니다. 이는 클라이언트 측에서 useFetch
를 기다리더라도 <script setup>
내에서 data
가 null로 남아 있음을 의미합니다.
옵션
useAsyncData
와 useFetch
는 동일한 객체 유형을 반환하고 마지막 인수로 공통의 옵션 세트를 수락합니다. 이들은 탐색 차단, 캐싱 또는 실행과 같은 composables의 동작을 제어하는 데 도움이 될 수 있습니다.
Lazy
기본적으로 데이터 가져오기 composables는 Vue의 Suspense를 사용하여 비동기 함수의 해결을 기다린 후 새 페이지로 탐색합니다. 이 기능은 클라이언트 측 탐색에서 lazy
옵션으로 무시할 수 있습니다. 이 경우, status
값을 사용하여 로딩 상태를 수동으로 처리해야 합니다.
<script setup lang="ts">
const { status, data: posts } = useFetch('/api/posts', {
lazy: true
})
</script>
<template>
<!-- 로딩 상태를 처리해야 합니다 -->
<div v-if="status === 'pending'">
로딩 중 ...
</div>
<div v-else>
<div v-for="post in posts">
<!-- 무언가를 수행 -->
</div>
</div>
</template>
대안으로 useLazyFetch
와 useLazyAsyncData
를 사용하여 동일한 작업을 수행할 수 있습니다.
const { status, data: posts } = useLazyFetch('/api/posts')
이것도 참고 api > composables > use-lazy-fetch
이것도 참고 api > composables > use-lazy-async-data
클라이언트 전용 가져오기
기본적으로 데이터 가져오기 composables는 클라이언트와 서버 환경 모두에서 비동기 함수를 수행합니다. server
옵션을 false
로 설정하여 클라이언트 측에서만 호출을 수행합니다. 초기 로드 시, 데이터는 하이드레이션이 완료될 때까지 가져오지 않으므로 보류 상태를 처리해야 하지만, 이후 클라이언트 측 탐색에서는 데이터를 기다린 후 페이지를 로드합니다.
lazy
옵션과 결합하여, 첫 번째 렌더링에 필요하지 않은 데이터(예: SEO에 민감하지 않은 데이터)에 유용할 수 있습니다.
/* 이 호출은 하이드레이션 전에 수행됩니다 */
const articles = await useFetch('/api/article')
/* 이 호출은 클라이언트에서만 수행됩니다 */
const { status, data: comments } = useFetch('/api/comments', {
lazy: true,
server: false
})
useFetch
composable은 setup 메소드에서 호출되거나 라이프사이클 훅의 함수 상단에서 직접 호출되도록 설계되었습니다. 그렇지 않으면 $fetch
메소드를 사용해야 합니다.
페이로드 크기 최소화
pick
옵션은 composables에서 반환되는 필드만 선택하여 HTML 문서에 저장되는 페이로드 크기를 최소화하는 데 도움이 됩니다.
<script setup lang="ts">
/* 템플릿에서 사용되는 필드만 선택 */
const { data: mountain } = await useFetch('/api/mountains/everest', {
pick: ['title', 'description']
})
</script>
<template>
<h1>{{ mountain.title }}</h1>
<p>{{ mountain.description }}</p>
</template>
더 많은 제어가 필요하거나 여러 객체를 매핑해야 하는 경우, transform
함수를 사용하여 쿼리 결과를 변경할 수 있습니다.
const { data: mountains } = await useFetch('/api/mountains', {
transform: (mountains) => {
return mountains.map(mountain => ({ title: mountain.title, description: mountain.description }))
}
})
pick
과 transform
모두 처음에 원치 않는 데이터를 가져오는 것을 방지하지는 않습니다. 그러나 서버에서 클라이언트로 전송되는 페이로드에 원치 않는 데이터가 추가되는 것을 방지합니다.
캐싱 및 다시 가져오기
키
useFetch
와 useAsyncData
는 동일한 데이터를 다시 가져오는 것을 방지하기 위해 키를 사용합니다.
useFetch
는 제공된 URL을 키로 사용합니다. 대안으로, 마지막 인수로 전달된options
객체에key
값을 제공할 수 있습니다.useAsyncData
는 첫 번째 인수를 키로 사용합니다. 첫 번째 인수가 쿼리를 수행하는 핸들러 함수인 경우,useAsyncData
인스턴스의 파일 이름과 줄 번호에 고유한 키가 자동으로 생성됩니다.
키로 캐시된 데이터를 가져오려면 useNuxtData
를 사용할 수 있습니다.
공유 상태 및 옵션 일관성
여러 구성 요소가 useAsyncData
또는 useFetch
와 동일한 키를 사용할 때, 동일한 data
, error
및 status
refs를 공유합니다. 이는 구성 요소 간의 일관성을 보장하지만 일부 옵션은 일관성을 유지해야 합니다.
다음 옵션은 동일한 키로 모든 호출에서 일관성을 유지해야 합니다:
handler
함수deep
옵션transform
함수pick
배열getCachedData
함수default
값
// ❌ 개발 경고를 트리거합니다
const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { deep: false })
const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { deep: true })
다음 옵션은 경고를 트리거하지 않고 안전하게 다를 수 있습니다:
server
lazy
immediate
dedupe
watch
// ✅ 허용됩니다
const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { immediate: true })
const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { immediate: false })
독립적인 인스턴스가 필요한 경우, 다른 키를 사용하세요:
// 이들은 완전히 독립적인 인스턴스입니다
const { data: users1 } = useAsyncData('users-1', () => $fetch('/api/users'))
const { data: users2 } = useAsyncData('users-2', () => $fetch('/api/users'))
반응형 키
키로 계산된 refs, 일반 refs 또는 getter 함수를 사용할 수 있어, 종속성이 변경될 때 자동으로 업데이트되는 동적 데이터 가져오기를 허용합니다:
// 계산된 속성을 키로 사용
const userId = ref('123')
const { data: user } = useAsyncData(
computed(() => `user-${userId.value}`),
() => fetchUser(userId.value)
)
// userId가 변경되면 데이터가 자동으로 다시 가져오고
// 다른 구성 요소에서 사용하지 않는 경우 이전 데이터가 정리됩니다
userId.value = '456'
새로 고침 및 실행
데이터를 수동으로 가져오거나 새로 고치려면, composables에서 제공하는 execute
또는 refresh
함수를 사용하세요.
<script setup lang="ts">
const { data, error, execute, refresh } = await useFetch('/api/users')
</script>
<template>
<div>
<p>{{ data }}</p>
<button @click="() => refresh()">데이터 새로 고침</button>
</div>
</template>
execute
함수는 즉시가 아닌 경우 더 의미 있는 경우에 대해 refresh
와 동일한 방식으로 작동하는 별칭입니다.
캐시된 데이터를 전역적으로 다시 가져오거나 무효화하려면 clearNuxtData
및 refreshNuxtData
를 참조하세요.
정리
특정 키를 clearNuxtData
에 전달할 필요 없이 제공된 데이터를 어떤 이유로든 정리하려면, composables에서 제공하는 clear
함수를 사용할 수 있습니다.
const { data, clear } = await useFetch('/api/users')
const route = useRoute()
watch(() => route.path, (path) => {
if (path === '/') clear()
})
감시
애플리케이션의 다른 반응형 값이 변경될 때마다 가져오기 함수를 다시 실행하려면, watch
옵션을 사용하세요. 하나 이상의 감시 가능한 요소에 사용할 수 있습니다.
const id = ref(1)
const { data, error, refresh } = await useFetch('/api/users', {
/* id가 변경되면 다시 가져옵니다 */
watch: [id]
})
반응형 값을 감시해도 가져온 URL은 변경되지 않습니다. 예를 들어, 이 경우 함수가 호출될 때 URL이 구성되므로 동일한 초기 ID의 사용자를 계속 가져옵니다.
const id = ref(1)
const { data, error, refresh } = await useFetch(`/api/users/${id.value}`, {
watch: [id]
})
반응형 값을 기반으로 URL을 변경해야 하는 경우, 대신 계산된 URL을 사용할 수 있습니다.
계산된 URL
때때로 반응형 값에서 URL을 계산하고, 이러한 값이 변경될 때마다 데이터를 새로 고쳐야 할 수 있습니다. 복잡한 방법을 사용하지 않고 각 매개변수를 반응형 값으로 연결할 수 있습니다. Nuxt는 반응형 값을 자동으로 사용하고 변경될 때마다 다시 가져옵니다.
const id = ref(null)
const { data, status } = useLazyFetch('/api/user', {
query: {
user_id: id
}
})
더 복잡한 URL 구성이 필요한 경우, URL 문자열을 반환하는 계산된 getter로 콜백을 사용할 수 있습니다.
종속성이 변경될 때마다 새로 구성된 URL을 사용하여 데이터를 가져옵니다. 즉시가 아닌과 결합하여, 반응형 요소가 변경될 때까지 기다렸다가 가져올 수 있습니다.
<script setup lang="ts">
const id = ref(null)
const { data, status } = useLazyFetch(() => `/api/users/${id.value}`, {
immediate: false
})
const pending = computed(() => status.value === 'pending');
</script>
<template>
<div>
{/* 가져오는 동안 입력을 비활성화 */}
<input v-model="id" type="number" :disabled="pending"/>
<div v-if="status === 'idle'">
사용자 ID를 입력하세요
</div>
<div v-else-if="pending">
로딩 중 ...
</div>
<div v-else>
{{ data }}
</div>
</div>
</template>
다른 반응형 값이 변경될 때 새로 고침을 강제하려면, 다른 값을 감시할 수도 있습니다.
즉시가 아님
useFetch
composable은 호출되는 순간 데이터를 가져오기 시작합니다. 예를 들어 사용자 상호작용을 기다리기 위해 immediate: false
로 설정하여 이를 방지할 수 있습니다.
이 경우, fetch 라이프사이클을 처리하기 위해 status
와 데이터를 가져오기 시작하기 위한 execute
가 필요합니다.
<script setup lang="ts">
const { data, error, execute, status } = await useLazyFetch('/api/comments', {
immediate: false
})
</script>
<template>
<div v-if="status === 'idle'">
<button @click="execute">데이터 가져오기</button>
</div>
<div v-else-if="status === 'pending'">
댓글 로딩 중...
</div>
<div v-else>
{{ data }}
</div>
</template>
더 세밀한 제어를 위해, status
변수는 다음과 같습니다:
idle
: 가져오기가 시작되지 않았을 때pending
: 가져오기가 시작되었지만 아직 완료되지 않았을 때error
: 가져오기가 실패했을 때success
: 가져오기가 성공적으로 완료되었을 때
헤더 및 쿠키 전달
브라우저에서 $fetch
를 호출할 때, cookie
와 같은 사용자 헤더는 API에 직접 전송됩니다.
일반적으로 서버 측 렌더링 동안 보안 고려 사항으로 인해 $fetch
는 사용자의 브라우저 쿠키를 포함하지 않으며, fetch 응답에서 쿠키를 전달하지 않습니다.
그러나 서버에서 상대 URL로 useFetch
를 호출할 때, Nuxt는 useRequestFetch
를 사용하여 헤더와 쿠키를 프록시합니다(전달되지 않아야 하는 헤더는 제외, 예: host
).
SSR 응답에서 서버 측 API 호출의 쿠키 전달
내부 요청에서 클라이언트로 쿠키를 전달하거나 프록시하려면, 이를 직접 처리해야 합니다.
import { appendResponseHeader } from 'h3'
import type { H3Event } from 'h3'
export const fetchWithCookie = async (event: H3Event, url: string) => {
/* 서버 엔드포인트에서 응답을 가져옵니다 */
const res = await $fetch.raw(url)
/* 응답에서 쿠키를 가져옵니다 */
const cookies = res.headers.getSetCookie()
/* 각 쿠키를 들어오는 요청에 첨부합니다 */
for (const cookie of cookies) {
appendResponseHeader(event, 'set-cookie', cookie)
}
/* 응답의 데이터를 반환합니다 */
return res._data
}
// 이 composable은 자동으로 쿠키를 클라이언트에 전달합니다
const event = useRequestEvent()
const { data: result } = await useAsyncData(() => fetchWithCookie(event!, '/api/with-cookie'))
onMounted(() => console.log(document.cookie))
Options API 지원
Nuxt는 Options API 내에서 asyncData
가져오기를 수행하는 방법을 제공합니다. 이를 위해 defineNuxtComponent
내에서 구성 요소 정의를 래핑해야 합니다.
export default defineNuxtComponent({
/* 고유 키를 제공하려면 fetchKey 옵션을 사용하세요 */
fetchKey: 'hello',
async asyncData () {
return {
hello: await $fetch('/api/hello')
}
}
})
<script setup>
또는 <script setup lang="ts">
는 Nuxt에서 Vue 컴포넌트를 선언하는 권장 방법입니다.
서버에서 클라이언트로 데이터 직렬화
서버에서 가져온 데이터를 클라이언트로 전송하기 위해 useAsyncData
및 useLazyAsyncData
를 사용할 때(및 Nuxt 페이로드를 활용하는 기타 모든 것), 페이로드는 devalue
로 직렬화됩니다. 이를 통해 기본 JSON뿐만 아니라 정규 표현식, 날짜, Map 및 Set, ref
, reactive
, shallowRef
, shallowReactive
및 NuxtError
와 같은 더 고급 데이터 유형을 직렬화하고 복원/역직렬화할 수 있습니다.
Nuxt에서 지원하지 않는 유형에 대해 자체 직렬화/역직렬화기를 정의할 수도 있습니다. useNuxtApp
문서에서 더 읽어볼 수 있습니다.
이것은 $fetch
또는 useFetch
로 가져온 서버 경로에서 전달된 데이터에는 적용되지 않습니다 - 더 많은 정보는 다음 섹션을 참조하세요.
API 경로에서 데이터 직렬화
server
디렉토리에서 데이터를 가져올 때, 응답은 JSON.stringify
를 사용하여 직렬화됩니다. 그러나 직렬화는 JavaScript 기본 유형으로만 제한되므로, Nuxt는 $fetch
및 useFetch
의 반환 유형을 실제 값과 일치하도록 최선을 다합니다.
예제
export default defineEventHandler(() => {
return new Date()
})
// `data`의 유형은 Date 객체를 반환했음에도 불구하고 문자열로 추론됩니다
const { data } = await useFetch('/api/foo')
사용자 정의 직렬화 함수
직렬화 동작을 사용자 정의하려면, 반환된 객체에 toJSON
함수를 정의할 수 있습니다. toJSON
메소드를 정의하면, Nuxt는 함수의 반환 유형을 존중하고 유형을 변환하려고 하지 않습니다.
export default defineEventHandler(() => {
const data = {
createdAt: new Date(),
toJSON() {
return {
createdAt: {
year: this.createdAt.getFullYear(),
month: this.createdAt.getMonth(),
day: this.createdAt.getDate(),
},
}
},
}
return data
})
// `data`의 유형은 다음과 같이 추론됩니다
// {
// createdAt: {
// year: number
// month: number
// day: number
// }
// }
const { data } = await useFetch('/api/bar')
대체 직렬화기 사용
Nuxt는 현재 JSON.stringify
에 대한 대체 직렬화기를 지원하지 않습니다. 그러나 페이로드를 일반 문자열로 반환하고 유형 안전성을 유지하기 위해 toJSON
메소드를 활용할 수 있습니다.
아래 예제에서는 superjson을 직렬화기로 사용합니다.
import superjson from 'superjson'
export default defineEventHandler(() => {
const data = {
createdAt: new Date(),
// 유형 변환을 우회합니다
toJSON() {
return this
}
}
// superjson을 사용하여 출력을 문자열로 직렬화합니다
return superjson.stringify(data) as unknown as typeof data
})
import superjson from 'superjson'
// `date`는 { createdAt: Date }로 추론되며 Date 객체 메소드를 안전하게 사용할 수 있습니다
const { data } = await useFetch('/api/superjson', {
transform: (value) => {
return superjson.parse(value as unknown as string)
},
})
레시피
POST 요청을 통한 SSE(서버 전송 이벤트) 소비
GET 요청을 통해 SSE를 소비하는 경우, EventSource
또는 VueUse composable useEventSource
를 사용할 수 있습니다.
POST 요청을 통해 SSE를 소비할 때, 연결을 수동으로 처리해야 합니다. 다음은 그 방법입니다:
// SSE 엔드포인트에 POST 요청을 보냅니다
const response = await $fetch<ReadableStream>('/chats/ask-ai', {
method: 'POST',
body: {
query: "Hello AI, how are you?",
},
responseType: 'stream',
})
// TextDecoderStream을 사용하여 데이터를 텍스트로 가져오기 위해 응답에서 새로운 ReadableStream을 생성합니다
const reader = response.pipeThrough(new TextDecoderStream()).getReader()
// 데이터를 받을 때마다 청크를 읽습니다
while (true) {
const { value, done } = await reader.read()
if (done)
break
console.log('Received:', value)
}
병렬 요청 수행
요청이 서로 의존하지 않는 경우, Promise.all()
을 사용하여 병렬로 수행하여 성능을 향상시킬 수 있습니다.
const { data } = await useAsyncData(() => {
return Promise.all([
$fetch("/api/comments/"),
$fetch("/api/author/12")
]);
});
const comments = computed(() => data.value?.[0]);
const author = computed(() => data.value?.[1]);
※이 페이지는 Nuxt.js 공식 문서의 비공식 번역 페이지입니다.
공식 문서의 해당 페이지는 여기 있습니다:
https://nuxt.com/docs/3.x/getting-started/data-fetching