Nuxt3项目实战篇6——数据请求篇,让你完美避过很多坑
上一篇我们学了组件的的使用与布局模板。 接下来是进行数据请求。
这一篇我们要解决的问题包含:
- 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 } }
如果你觉得我写的好,记得关注+收藏哦。 如果要转载,请标注文章来源。