$fetch
Nuxt 中进行HTTP调用的首选方式
const users = await $fetch('/api/users').catch((error) => error.data)
缺陷:不会提供网络请求重复和导航阻止
<script setup lang="ts">
// 在SSR中数据将被获取两次,一次在服务器端,一次在客户端。
const dataTwice = await $fetch('/api/item')
</script>
适用场景:
-
提交数据到事件处理程序
-
在客户端逻辑中使用
<script setup lang="ts"> function contactForm() { $fetch('/api/contact', { method: 'POST', body: { hello: 'world '} }) } </script> <template> <button @click="contactForm">联系我们</button> </template>
-
与 useAsyncData 结合使用
// 在SSR中,数据仅在服务器端获取并传递到客户端。 const { data } = await useAsyncData('item', () => $fetch('/api/item'))
专用的组合式函数
为了避免重复的网络请和实现导航阻止,Nuxt 提供了专门的组合式函数来进行网络请求。
useAsyncData
const { data, error } = await useAsyncData('users', () => myGetFunction('users'))
第一个参数是用于缓存第二个参数(查询函数)的响应的唯一键,若第一个参数就传入函数,则唯一键会自动生成
useAsyncData 使用唯一键来防止重新获取相同的数据。( 使用 useNuxtData 可根据键获取缓存的数据 )
建议始终创建自己的键以避免不需要的行为
useAsyncData 是等待多个请求的绝佳方式。
const { data: discounts, pending } = await useAsyncData(
"cart-discount",
async () => {
const [coupons, offers] = await Promise.all([
$fetch("/cart/coupons"),
$fetch("/cart/offers"),
]);
return {
coupons,
offers,
};
}
);
useFetch
可看作 useAsyncData + $fetch 的快捷方式
useFetch 使用 URL 或 选项中提供的 key 值作为唯一键来防止重新获取相同的数据。( 使用 useNuxtData 可根据键获取缓存的数据 )
const { data: count } = await useFetch('/api/count')
不适合的场景:
- CMS 或第三方提供自己的查询层时 (此时建议用 useAsyncData)
懒加载(先导航)lazy
组合函数默认会等待数据请求完成后,再执行导航
通过 lazy 选项可以改为先导航,此时需使用pending值手动处理加载状态
<script setup lang="ts">
const { pending, data: posts } = useFetch('/api/posts', {
lazy: true
})
</script>
<template>
<!-- 你需要处理加载状态 -->
<div v-if="pending">
加载中...
</div>
<div v-else>
<div v-for="post in posts">
<!-- 做一些操作 -->
</div>
</div>
</template>
使用 useLazyFetch 和 useLazyAsyncData 可更方便地相同的操作。
const { pending, data: posts } = useLazyFetch('/api/posts')
仅在客户端获取数据 server
组合函数默认在客户端和服务器环境中都会执行异步函数。
将 server 选项设置为 false,则只在客户端执行调用。
与 lazy 选项结合使用,特别适合首次渲染不需要的数据(例如,非SEO敏感数据)
/* 此调用仅在客户端执行 */
const { pending, data: posts } = useFetch('/api/comments', {
lazy: true,
server: false
})
useFetch组合函数用于在设置方法中调用,或在生命周期钩子函数的函数顶层直接调用,否则你应该使用 $fetch 方法。
限定返回字段 pick
/* 仅选择模板中使用的字段 */
const { data: mountain } = await useFetch('/api/mountains/everest', { pick: ['title', 'description'] })
pick 不会阻止初始时获取不需要的数据,但会阻止不需要的数据被添加到从服务器传输到客户端的 html 中,从而减少有效负载大小
修改查询结果 transform
const { data: mountains } = await useFetch("/api/mountains", {
transform: (mountains) => {
return mountains.map((mountain) => ({
title: mountain.title,
description: mountain.description,
}));
},
});
transform 不会阻止初始时获取不需要的数据,但会阻止不需要的数据被添加到从服务器传输到客户端的 html 中,从而减少有效负载大小
刷新数据 refresh
请使用组合函数提供的 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 的别名,使用方式完全相同,但在非立即的情况下更语义化。
刷新所有数据 refreshNuxtData
<script setup lang="ts">
const refreshing = ref(false)
const refreshAll = async () => {
refreshing.value = true
try {
await refreshNuxtData()
} finally {
refreshing.value = false
}
}
</script>
<template>
<div>
<button :disabled="refreshing" @click="refreshAll">
重新获取所有数据
</button>
</div>
</template>
刷新特定数据
如:只刷新与 count 键匹配的数据
<script setup lang="ts">
const { pending, data: count } = await useLazyAsyncData('count', () => $fetch('/api/count'))
const refresh = () => refreshNuxtData('count')
</script>
<template>
<div>
{{ pending ? '加载中' : count }}
</div>
<button @click="refresh">刷新</button>
</template>
监听刷新 watch
使用 watch 选项,监听一个或多个响应式值,当其更改时重新运行获取函数
const id = ref(1)
const { data, error, refresh } = await useFetch('/api/users', {
/* 更改id将触发重新获取 */
watch: [id]
})
监视响应式值不会更改获取的URL。
动态 URL
随响应式值变化的 URL在每次更改时都会重新获取数据
const id = ref(null)
const { data, pending } = useLazyFetch('/api/user', {
query: {
user_id: id
}
})
与非立即结合使用,可以在响应元素更改之前等待获取。
<script setup lang="ts">
const id = ref(null)
const { data, pending, status } = useLazyFetch(() => `/api/users/${id.value}`, {
immediate: false
})
</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>
阻止立即执行 immediate: false
默认组合函数会立即开始获取数据,通过设置 immediate: false 可阻止立即执行
此时需要使用 status 来处理获取生命周期,并使用 execute 来开始数据获取。
<script setup lang="ts">
const { data, error, execute, pending, status } = await useLazyFetch('/api/comments', {
immediate: false
})
</script>
<template>
<div v-if="status === 'idle'">
<button @click="execute">获取数据</button>
</div>
<div v-else-if="pending">
加载评论中...
</div>
<div v-else>
{{ data }}
</div>
</template>
status 变量可能的取值有:
- idle:获取未开始
- pending:获取已开始但尚未完成
- error:获取失败
- success:获取成功完成
清除缓存数据 clearNuxtData
可删除 useAsyncData 和 useFetch的缓存数据、错误状态和待处理的 promises,用于使另一个页面的数据获取失效
参数为键,如果没有提供键,将会使所有数据失效。