Nuxt3项目实战篇6——数据请求篇,让你完美避过很多坑
匿名 · 更新于 2022/10/23
上一篇我们学了组件的的使用与布局模板。 接下来是进行数据请求。
这一篇我们要解决的问题包含:
- 1. Nuxt3的数据请求跨域解决方案;
- 2. Nuxt3中的的post请求怎么实现;
- 3. Nuxt3的数据请求中的各个参数的意义;
Nuxt3中的数据请求? fetch还是axios? 个人认为,看自己的心情。 那要不要引入axios?
- 利:熟悉,使用起来方便,上手快, 赶项目的话,不需要时间磨合
- 弊:Nuxt3框架自己封装了数据请求,再引入axios, 增加了打包的体积(这点体积反正我不是很在乎)。
axios我们不再阐述,不过Nuxt3建议我们使用$fetch进行数据请求。
一. 首先,NUXT3跨域解决方案:在NUXT.CONFIG.JS中配置
export default defineNuxtConfig({
...
vite: {
server: {
proxy: {
'/api': {
target: 'http://www.xxx.net', //这里是接口地址
changeOrigin: true
},
'^/api': {
target: 'http://xxx.com', //这里是接口地址
changeOrigin: true
},
},
}
},
}
二、 关于$FETCH
$fetch是Nuxt3对ohmyfetch的封装. 在服务器端渲染期间,调用$fetch获取内部API 路由将直接调用相关函数(模拟请求),节省额外的 API 调用。请注意,$fetch是Nuxt 3中进行 HTTP请求的首选方式,而不是为 Nuxt 2 进行的@nuxt/http和@nuxtjs/axios。$fetch的使用方法可以参考api .
const { users } = await $fetch('/api/users', { method: 'POST', body: { some: 'json' } })
// Adding baseURL
await $fetch('/config', { baseURL })
// Adding params
await $fetch('/movie?lang=en', { params: { id: 123 } })
//Handling Errors
await $fetch(...).catch((error) => error.data)
三、NUXT3数据获取方法
nuxt3 中内置了四种请求数据的方法,
- useFetch
- useLazyFetch
- useAsyncData
- useLazyAsyncData
1. useAsyncData方法:在页面、组件、插件中使用该方法异步获取数据,可以反序列化响应返回的 JSON 对象。
function useAsyncData(
key: string,
handler: (nuxtApp?: NuxtApp) => Promise<DataT>,
options?: AsyncDataOptions<DataT>
): Promise<AsyncData<DataT>>
const {
data: Ref<DataT>, // 异步函数的结果
pending: Ref<boolean>, // 加载状态指示器,一个布尔值,指示是否仍在获取数据
refresh: (force?: boolean) => Promise<void>, // 强制刷新函数,可以用来刷新handler函数
error?: any // 请求失败的错误信息
} = useAsyncData(
key: string,// 唯一键用于多次请求结果去重
fn: () => Object,// 返回请求的promise函数
options?: { lazy: boolean, server: boolean, pick:{ } } // lazy:是否在路由之后才请求数据, 默认为false,server:是否在服务端请求数据,默认为true, pick:函数结果中选择指定键的数据
)
怎么使用useAsyncData
<script setup>
const { data: result, pending, error, refresh } = await useAsyncData(
apiurl, //key
() => $fetch(url) //数据请求
)
</script>
注意:1. useAsyncData从目前官网的情况看,只能发送get请求。2. key值唯一,否则会发生一些意想不到的错误。最明显的错误就是不发送请求。且在Nuxt3中的数据请求不需要放在生命周期onMounted里,经过反复实验,请求放在onMounted中有两个弊端:
- 虽然有发送请求,但是数据请求回来后,数据代理出来的value为null
- 数据渲染的时候页面有抖动现象
2. useLazyAsyncData,默认情况下,useAsyncData 会阻塞路由导航,直到它的异步处理程序被解析。useLazyAsyncData是通过将lazy选项设置为true的useAsyncData的包装器. useLazyAsyncData的参数与useAsyncData几乎一致.
function useAsyncData(
key: string,
handler: (nuxtApp?: NuxtApp) => Promise<DataT>,
options?: AsyncDataOptions<DataT>
): Promise<AsyncData<DataT>>
const {
data: Ref<DataT>, // 异步函数的结果
pending: Ref<boolean>, // 加载状态指示器,一个布尔值,指示是否仍在获取数据
refresh: (force?: boolean) => Promise<void>, // 强制刷新函数,可以用来刷新handler函数
error?: any // 请求失败的错误信息
} = useLazyAsyncData(
key: string,// 唯一键用于多次请求结果去重
fn: () => Object,// 返回请求的promise函数
options?: { lazy: boolean, server: boolean, pick:{ } } // lazy:是否在路由之后才请求数据, 默认为false,server:是否在服务端请求数据,默认为true, pick:函数结果中选择指定键的数据
)
使用方法
<script setup>
const { pending, data: count } = useLazyAsyncData('count', () => $fetch('/api/count'))
watch(count, (newCount) => {
// Because count starts out null, you won't have access
// to its contents immediately, but you can watch it.
})
</script>
有没有发现一个问题?到目前为止,asyncData我们只能get数据,没有post方法吗?
3. useFetch:封装了useAsyncData和$fetch, 它会根据URL和fetch选项自动生成key,并推断API响应类型。默认情况下,useFetch 会阻止导航,直到它的异步处理程序被解析。
const {
data: Ref<DataT> //传入的异步函数的结果
pending: Ref<boolean> //: 一个布尔值,指示是否仍在获取数据
refresh: () => Promise<void> //一个函数,可以用来刷新handler函数 返回的数据
error: Ref<Error | boolean> //数据获取失败时的错误对象
} = await useFetch(
url, //api的url
options ?: {
key?: string, //一个唯一的key,确保数据获取可以跨请求正确去重,可以手动设置,如果没有提供,它将根据url和fetch选项 生成,
method?: string, //请求方法, get/post/put....
params?: SearchParams, // 查询参数
body?: RequestInit['body'] | Record<string, any> //请求正文 - 自动字符串化(如果传递了一个对象)。
headers?: { key: string, value: string }[], //请求头设置
baseURL?: string, //请求的baseURL
server?: boolean //是否获取服务器上的数据(默认为true)。
lazy?: boolean //加载路由后是否解析异步函数,而不是阻塞导航(默认为false)。
default?: () => DataT //在异步函数解析之前设置数据默认值的工厂函数 - 对于该lazy: true选项特别有用。
transform?: (input: DataT) => DataT //解析后 可用于改变函数结果的函数.
pick?: string[] //仅从handler函数结果中选择此数组中的指定键。注意:是json数组中的某个字段. 只能过滤简单的数据,transform 可以精细的选择
watch?: WatchSource[] //观察反应源以自动刷新
initialCache?: boolean //当设置为 时false,将跳过有效负载缓存以进行初始提取。(默认为true)
}
)
使用方法
<script setup>
const { data: result, pending, error, refresh } = await useFetch(
url,
{
method: 'post',
pick: ['slide']
}
)
</script>
<template>
Page visits: {{ data}}
</template>
4. useLazyFetch:与useFetch类似,useLazyFetch提供了一个包装器useFetch,通过将lazy选项设置为true. 就不会阻塞路由导航了。且useLazyFetch和useAsyncData类似.
如果只是简单的get函数,直接使用useAsyncData就行了,但是post等其他请求方式和需要带参数就只能使用useFetch与useLazyFetch
问题来了:
1)、 useFetch和useAsyncData有什么区别?
- a. useFetch接收一个 URL并获取该数据,而useAsyncData可能有更复杂的逻辑。useFetch(url)几乎等同于useAsyncData(url, () => $fetch(url))。 useFetch是useAsyncData的封装
- b. useAsyncData是最常见用例的开发人员体验糖。useAsyncData,做一些简单的get数据请求,useFetch可以做更复杂的post、put、delete等请求。
2)、 useAsyncData与useLazyAsyncData的区别:
- useLazyAsyncData是useAsyncData的lazy:true的封装。
- useLazyAsyncData是异步函数,不会阻塞导航, 但是pending时它的初始值为null, 开始的时候不能立马访问,可以通过watch监听拿到数据
目前,在数据请求中我遇到的几个坑
1. 数据不发送请求,需要刷新一下才请求数据:
问题查找:检查一下你template下是否为多节点.
2. 数据请求了,控制台也能看到, 但是打印的value值为null;
解决办法:数据请求直接放在setup下,不用放在生命周期的onMounted中;
3. 打印结果不为null, 但是未渲染到页面上去:
解决办法:在渲染的div上添加v-if判断数据是否存在
四、 高级用法
1. 我们可以用refresh做选择分页、过滤结果、搜索等功能,直接使用refresh就可以获取对应参数的数据
<script setup>
const page = ref(1);
const { data: users, pending, refresh, error } = await useFetch(() => `users?page=${page.value}&take=6`, { baseURL: config.API_BASE_URL });
function previous(){
page.value--;
refresh();
}
function next() {
page.value++;
refresh();
}
</script>
2. refreshNuxtData用于刷新数据
<template>
<div>
{{ pending ? 'Loading' : count }}
</div>
<button @click="refresh">Refresh</button>
</template>
<script setup>
const { pending, data: count } = useLazyAsyncData('count', () => $fetch('/api/count'))
const refresh = () => refreshNuxtData('count')
</script>
使用异步设置, 如果你正在使用async setup(),当前的组件实例会在第一个请求之后丢失await(这是 Vue 3 的限制)。如果要使用多个异步操作,多次调用useFetch,建议使用promise.all()
<script>
export default defineComponent({
async setup() {
const [{ data: organization }, { data: repos }] = await Promise.all([
useFetch(`https://api.github.com/orgs/nuxt`),
useFetch(`https://api.github.com/orgs/nuxt/repos`)
])
return {
organization,
repos
}
}
})
</script>
<template>
<header>
<h1>{{ organization.login }}</h1>
<p>{{ organization.description }}</p>
</header>
</template>
到了最后,我们来开个火箭。每次都在setup中写$fetch请求实在麻烦,我们直接封装一个函数放在composables文件下,然后在setup中直接调用就可以了
export const getData = async (url,methods='get', params={}) => {
const { data: result, pending, error, refresh } = await useLazyFetch(
url,
{
params,
method
}
)
watch(result, newValue => {
})
if (result.value) {
return result.value.data
}
}
如果你觉得我写的好,记得关注+收藏哦。 如果要转载,请标注文章来源。
