数据获取
Nuxt 提供了组合式函数来处理应用中的数据获取。
Nuxt 配备了两个组合式函数和一个内置库,用于在浏览器或服务器环境中执行数据获取:useFetch、useAsyncData 和 $fetch。
简而言之:
$fetch是发起网络请求的最简单方式。useFetch是$fetch的封装,确保在通用渲染过程中只获取一次数据。useAsyncData类似于useFetch,但提供了更细粒度的控制。
useFetch 和 useAsyncData 共享一套通用的选项和模式
HTML水合
HTML 水合 是指一个过程:在客户端(浏览器)将 JavaScript 逻辑(如交互事件处理程序、状态、生命周期等)“附加”或“注入”到由服务端发送来的静态 HTML 页面中的过程。
你可以把它想象成一个“复活”或“赋予生命”的过程:
- 服务端 生成了一个完整的、但却是“静态”的 HTML 结构。它就像一具没有灵魂的躯体。
- 客户端 接收到这个 HTML 并立即展示给用户(这带来了快速的初始加载体验)。
- 随后,客户端下载的 JavaScript 包开始执行。这个 JavaScript 包包含了创建交互式应用程序所需的所有逻辑。
- 这个 JavaScript 会“接管”现有的静态 HTML,将其与背后的虚拟 DOM、组件树、状态管理等进行关联,并为其绑定事件监听器(如
onClick,onChange)。 - 至此,原本静态的页面就被“水合”了——它变得完全可交互,就像一个正常的单页面应用(SPA)一样。
为什么需要useFetch和useAsyncData
Nuxt 是一个能够在服务器和客户端环境中运行同构(或通用)代码的框架。如果在 Vue 组件的 setup 函数中直接使用 $fetch 函数 来执行数据获取,可能会导致数据被获取两次:一次在服务器端(用于渲染 HTML),一次在客户端(HTML 水合时)。这会引发水合问题,增加交互时间,且可能导致不可预测的行为。
useFetch 和 useAsyncData 通过确保如果在服务器上调用了 API,则数据会通过负载转发给客户端,从而解决了这个问题。
负载是一个 JavaScript 对象,通过 useNuxtApp().payload 访问。它在客户端用于避免在浏览器执行代码水合期间重复获取相同数据。
<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 没有此机制,更适合仅在浏览器端发起请求的场景。
$fetch
Nuxt已内置了ofetch库,并全局导入成$fetch
<script setup lang="ts">
async function addTodo() {
const todo = await $fetch('/api/todos', {
method: 'POST',
body: {
// 我的待办数据
}
})
}
</script>向API传递客户端请求头
看不懂啊
useFetch
useFetch 组合函数基于 $fetch
useFetch 会在 服务端渲染 (SSR) 时自动调用,返回的数据会直接注入到 HTML 中。
如果请求的 URL 是相对路径 /api/hello,Nuxt 会自动代理到服务端 API。
<script setup lang="ts">
const { data: count } = await useFetch('/api/count')
</script>
<template>
<p>页面访问次数:{{ count }}</p>
</template>useAsyncData
useAsyncData 组合函数是包装并等待多个 $fetch 请求完成后处理结果的绝佳方式。
<script setup lang="ts">
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
</script>返回值
useFetch 和 useAsyncData 返回相同的对象,包含如下内容:
data: 传入的异步函数结果。refresh/execute: 用于刷新由handler函数返回的数据。clear: 用于将data设为undefined(或提供的options.default()的值),error设为null,status设为idle,并将当前所有待定请求标记为取消。error: 数据获取失败时的错误对象。status: 表示数据请求状态的字符串("idle"、"pending"、"success"、"error")。
警告
data、error 和 status 是 Vue 的 ref,在 <script setup> 中用 .value 访问。
