Nuxt3提供了4种形式使得咱们能够异步获取数据
- useAsyncData
- useLazyAsyncData (useAsyncData+lazy:true)
- useFetch
- useLazyFetch (useFetch+lazy:true)
4种形式中,其实外围的就是useAsyncData
和useFetch
。这两个办法不同于Nuxt2中的asyncData
和fetch
。接下来咱们先来好好剖析下这两个办法。
useAsyncData
咱们晓得,在Nuxt2中,asyncData
办法相似于一个生命周期函数,它在服务端或路由更新之前被调用。办法的参数是以后页面的上下文对象,咱们个别是利用 asyncData
办法来获取数据并返回给以后组件,以防止申请放在客户端执行时带来的数据提早呈现问题。
export default { data() { return { project: 'default' } }, asyncData(context) { return { project: 'nuxt' } }}
在Nuxt3中,useAsyncData
能够看做是异步获取数据场景的一个封装,而且变成了一个被动调用函数,原则上能够在任何机会调用。
// 用法const { data: Ref<DataT>,// 返回的数据后果 pending: Ref<boolean>,// 是否在申请状态中 refresh: (force?: boolean) => Promise<void>,// 强制刷新数据 error?: any // 申请失败返回的错误信息} = useAsyncData( key: string, // 惟一键,确保雷同的申请数据的获取和去重 fn: () => Object,// 一个返回数值的异步函数 options?: { lazy: boolean, server: boolean } // options.lazy,是否在加载路由后才申请该异步办法,默认为false // options.server,是否在服务端申请数据,默认为true // options.default,异步申请前设置数据data默认值的工厂函数(对lazy:true选项特地有用) // options.transform,更改fn返回后果的函数 // options.pick,只从数组中指定的key进行缓存)
从api的设计中能够看出,useAsyncData
没有限度咱们发动网络申请的形式,同时它还裸露了申请状态,减少了刷新管制,以及对反复获取数据的去重管制等。
应用示例如下:
<script setup>const { data } = await useAsyncData('count', () => $fetch('/api/count'))</script><template> Page visits: {{ data }}</template>
useFetch
在Nuxt2中,fetch 办法用于在渲染页背后填充利用的状态树(store)数据, 与 asyncData 办法相似,不同的是它不会设置组件的数据。
<template> <h1>Stars: {{ $store.state.stars }}</h1></template><script> export default { fetch({ store, params }) { return axios.get('http://my-api/stars').then(res => { store.commit('setStars', res.data) }) } }</script>
在Nuxt3中,useFetch
实际上是对useAsyncData
和$fetch
的封装,提供了一个更便捷的封装办法。它相比useAsyncData
, 次要做了以下两点解决:
- 它会依据URL和fetch参数主动生成一个key,同时推断出API的响应类型。也就是说不必手动指定key了。
它实现了网络申请的具体形式,应用
$fetch
发动申请,也就是说不须要再手动去实现网络申请的逻辑了。//useFetch用法const { data: Ref<DataT>, pending: Ref<boolean>, refresh: (force?: boolean) => Promise<void>, error?: any} = useFetch(url: string, options?)// options (继承自 unjs/ofetch options以及 AsyncDataOptions)// 下边的这些参数是useAsyncData的options中没有的// options.method: 申请形式// options.query: url门路参数// options.params: query参数的别名// options.body: 申请体参数,// options.headers: 申请头的配置// options.baseURL: 申请的根底Url地址
实战利用
咱们不难发现,
useFetch
曾经具备了网络申请的所有外围性能,尽管该Api次要用于在服务端申请,但它也是做了客户端申请的反对的,只有稍加封装改变,就能够同时用于服务端申请和客户端申请的场景。这样咱们也就不必额定再引入像Axios
这样的申请库了。场景1: 如何解决对于带错误码的数据响应
通常咱们的接口都不是间接返回数据,而是带了一个错误码和错误信息的对象,比方这样:
// response:{ data: {age: 1}, code: 1}
在这样的返回构造下,
useFetch
拿到的数据并不是咱们实在想要的数据const { data } = await useFetch('/api/user/info', { method: 'get'})console.log(data) // 此时data是一个Ref包裹的对象{ data: {age: 1}, code: 1 }const userInfo = unref(data).data //获取真正的数据须要先unref后再去获取data
所以,咱们心愿能在接口返回时对数据做一下转换,这里其实
useFetch
提供了相干的option参数,咱们能够这样批改const { data: userInfo} = await useFetch('/api/user/info', { method: 'get', // 解决形式1 onResponse({ response }) { response._data = { ...response._data.data, } }, // 解决形式2 // transform: (res) => { // return res.data // },})
场景2: 如何只在客户端侧发动申请
这样的场景个别用于应用动态化构建部署,然而页面上有些内容是不能在构建时动态化的。这时能够利用
server:false
参数// 异步获取以后用户信息const { data: userinfo } = await useMyFetch('/api/auth/userinfo', { server: false})
留神: 这种状况下,如果想在script内间接获取到userinfo的外部值,是获取不到的!官网文档也做了对应的阐明:
if you have not fetched data on the server (for example, with
server: false
), then the data will not be fetched until hydration completes. This means even if you await useFetch on client-side, data will remain null within<script setup>
.
如果非要在script中获取数据呢?这里笔者想到两个计划:
- 用
$fetch
去发动申请 用
watch
监听userinfo
的值变动场景3: 如何将申请后果转为非响应式的数据
这种场景个别用于在客户端发动的申请,咱们不须要在页面上渲染响应的数据,只是为了做一些逻辑判断或者须要对数据进行加工。而
useFetch
申请后的返回值默认都是一个ref对象,咱们得先获取外部值。const { data } = await useMyFetch('/api/get-actiocn-token')// data是一个Ref包裹的对象,须要用unref获取外部值const tokenInfo = unref(data)
如果想间接获取原始数据的话,
useFetch
原生是不反对的(或者是我当初还不晓得怎么实现)。咱们只能应用$fetch
去实现了。
申请对立封装
针对上述三种场景,笔者分享下本人的封装思路,即在composables
目录中实现一个useMyFetch办法,去解决一些通用的逻辑
import type { NitroFetchRequest } from 'nitropack'import type { FetchOptions, FetchResponse } from 'ofetch'import type { UseFetchOptions } from 'nuxt/dist/app/composables/fetch'function transFormResponse({ response }: any) { // 解决后端携带了错误码响应的数据 if (response._data && response._data.code) return Promise.reject(response._data) response._data = { ...response._data.data, }}/** * 封装$fetch用于简略申请场景 * @param request * @param opts * @returns */export function useClientFetch(request: NitroFetchRequest, opts?: FetchOptions<any>) { return $fetch<FetchResponse<any>>(request, { onResponse: transFormResponse, ...opts, })}/** * 抽离useFetch的通用配置 * @param request * @param opts * @returns */export function useMyFetch(request: NitroFetchRequest, opts?: UseFetchOptions<any>) { return useFetch(request, { onResponse: transFormResponse, ...opts, })}/** * 实现更便捷的post申请 * @param request * @param opts * @returns */useMyFetch.get = (request: NitroFetchRequest, opts?: UseFetchOptions<any>) => { return useMyFetch(request, { method: 'get', ...opts, })}/** * 实现更便捷的post申请 * @param request * @param opts * @returns */useMyFetch.post = (request: NitroFetchRequest, opts?: UseFetchOptions<any>) => { return useMyFetch(request, { method: 'post', ...opts, })}
结语
博客原创地址:Nuxt3实战系列之网络申请篇
分割作者:whitney1289(微信),iwhitney@163.com(邮箱)