Skip to content

数据获取

Nuxt 提供了组合函数来处理应用程序中的数据获取

  • useFetch:是在组件设置函数中处理数据获取的最简单的方法

  • $fetch:可以根据用户交互进行网络请求

  • useAsyncData:结合$fetch提供更精细的控制

useFetchuseAsyncData 共享一组常见的选项和模式,在后面的章节中我们将详细介绍。

在此之前,首先要知道为什么需要这些组合函数。

useFetch

useFetch 组合函数是执行数据获取的最简单的方法。

  • 这里要使用解构赋值来获取数据,因为 useFetch 返回一个响应对象,该对象包含 dataerror 等等属性。
html
<script setup lang="ts">
  const { data: count } = await useFetch("/api/count");
</script>

<template> 页面访问量:{{ count }} </template>

$fetch

Nuxt 包括了 ofetch 库,并且作为全局别名 $fetch 自动导入到应用程序中。它是 useFetch 在幕后使用的工具

使用方法

  • 一般就是点击事件获取数据

  • 和 useAsyncData 结合使用

html
<script setup lang="ts">
  const login = () => {
    const result = await $fetch("/auth/login", {
      method: "POST",
      body: {
        username: "username",
        password: "password",
      },
    });
  };
</script>

<template>
  <div>
    <button @click="login">登录</button>
  </div>
</template>

INFO

请注意,仅使用 $fetch 将不会提供 网络请求重复和导航阻止。建议在提交数据到事件处理程序时使用 $fetch,在客户端逻辑中使用,或与 useAsyncData 结合使用。

useAsyncData

seAsyncData 组合函数负责封装异步逻辑并在解析完成后返回结果。

事实上,useFetch(url) 几乎等同于 useAsyncData(url, () => $fetch(url)) - 它是为最常见的用例提供的开发者体验糖。

在某些情况下,使用 useFetch 组合函数是不合适的,例如当 CMS 或第三方提供自己的查询层时。在这种情况下,您可以使用 useAsyncData 来封装您的调用,并仍然保持组合函数提供的好处。

useAsyncData 的第一个参数是用于缓存第二个参数(查询函数)的响应的唯一键。如果直接传递查询函数,则可以忽略该参数。在这种情况下,它将自动生成。

特别注意第一个参数不能重复:一般用接口地址作为键位

单独

js
const { data, error } = await useAsyncData("users", () =>
  myGetFunction("users")
);

组合

useAsyncData 组合函数是包装和等待多个 useFetch 完成,并获取每个结果的绝佳方式。

js
const { data: discounts, pending } = await useAsyncData(
  "cart-discount",
  async () => {
    const [coupons, offers] = await Promise.all([
      $fetch("/cart/coupons"),
      $fetch("/cart/offers"),
    ]);

    return {
      coupons,
      offers,
    };
  }
);
  • 页面使用的时候就是
html
<h1>{{discount.offers}}</h1>
<h2>{{discount.coupons}}</h2>

选项

懒加载(lazy)

默认情况下,数据获取的组合函数会在异步函数解析完成之前使用 Vue 的 Suspense 进行页面导航。通过使用 lazy 选项,可以忽略此功能在客户端导航时的使用。在这种情况下,你需要手动处理加载状态,使用 pending 值。

  • 组件里面

通过 pedding 来控制加载状态

html
<script setup lang="ts">
  const { pending, data: posts } = useFetch("/api/posts", {
    lazy: true,
  });
</script>

<template>
  <!-- 你需要处理加载状态 -->
  <div v-if="pending">加载中...</div>
  <div v-else>
    <div v-for="post in posts">
      <!-- 做一些操作 -->
    </div>
  </div>
</template>

你还可以使用useLazyFetchuseLazyAsyncData作为方便的方法来执行相同的操作。

js
const { pending, data: posts } = useLazyFetch("/api/posts");
  • 仅仅在客户端中调用

通过server选项来控制

js
const { data: posts } = useFetch("/api/posts", {
  server: false,
  lazy: true,
});

获取有效字段(pick)

  • 通过pick选项来控制
html
<script setup lang="ts">
  /* 仅选择模板中使用的字段 */
  const { data: mountain } = await useFetch("/api/mountains/everest", {
    pick: ["title", "description"],
  });
</script>

<template>
  <h1>{{ mountain.title }}</h1>
  <p>{{ mountain.description }}</p>
</template>

刷新(refresh)

  • 如果要手动获取或刷新数据,请使用组合函数提供的 executerefresh 函数。
html
<script setup lang="ts">
  const { data, error, execute, refresh } = await useFetch("/api/users");
</script>

<template>
  <div>
    <p>{{ data }}</p>
    <button @click="refresh">刷新数据</button>
  </div>
</template>

发送参数(query)

  • 通过 query 选项来控制
js
const id = ref(null);

const { data, pending } = useLazyFetch("/api/user", {
  query: {
    user_id: id,
  },
});

状态

html
<script setup lang="ts">
  const { data, error, execute, pending, status } = await useLazyFetch(
    "/api/comments"
  );
</script>

<template>
  <div v-if="status === 'idle'">
    <button @click="execute">获取数据</button>
  </div>

  <div v-else-if="pending">加载评论中...</div>

  <div v-else>{{ data }}</div>
</template>

为了更精细的控制,status 分成了以下几种

  • idle:获取未开始
  • pending:获取已开始但尚未完成
  • error:获取失败
  • success:获取成功完成

当我们在浏览器中调用 $fetch 时,用户的请求头(如 cookie)会直接发送到 API。但在服务器端渲染期间,由于 $fetch 请求在服务器内部进行,它不包含用户浏览器的 Cookie,也不会传递来自获取响应的 Cookie

将客户端请求头传递到 API

我们可以使用 useRequestHeaders 来访问和代理服务器端的 Cookie 到 API。

下面的示例将请求头添加到同构的 $fetch 调用中

以确保 API 端点能够访问用户最初发送的相同 cookie 请求头。

html
<script setup lang="ts">
  const headers = useRequestHeaders(["cookie"]);

  const { data } = await useFetch("/api/me", { headers });
</script>