关于vue3:Nuxt3实战系列之网络请求篇

37次阅读

共计 4647 个字符,预计需要花费 12 分钟才能阅读完成。

Nuxt3 提供了 4 种形式使得咱们能够异步获取数据

  • useAsyncData
  • useLazyAsyncData(useAsyncData+lazy:true)
  • useFetch
  • useLazyFetch(useFetch+lazy:true)

4 种形式中,其实外围的就是 useAsyncDatauseFetch。这两个办法不同于 Nuxt2 中的 asyncDatafetch。接下来咱们先来好好剖析下这两个办法。

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, 次要做了以下两点解决:

  1. 它会依据 URL 和 fetch 参数主动生成一个 key,同时推断出 API 的响应类型。也就是说不必手动指定 key 了。
  2. 它实现了网络申请的具体形式,应用 $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 中获取数据呢?这里笔者想到两个计划:

  1. $fetch 去发动申请
  2. 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(邮箱)

正文完
 0