Nuxt3项目实战篇6——数据请求篇,让你完美避过很多坑

2022-07-26 13:47:22

上一篇我们学了组件的的使用与布局模板。 接下来是进行数据请求。

这一篇我们要解决的问题包含:

  • 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
  }
}

如果你觉得我写的好,记得关注+收藏哦。 如果要转载,请标注文章来源。

关于

联系方式 :

mail: hey_cool@163.com ,
QQ:583459700

备案许可证编号:蜀ICP备16005545号-1 © COPYRIGHT 2015-2022 zhmzjl.com | by: KAPO