NuxtJS的 AsyncData 和 Fetch 使用详解

asyncData

简介

asyncData 可以用来在客户端加载 Data 数据之前对其做一些处理,也可以在此发起异步请求,提前设置数据,这样在客户端加载页面的时候,就会直接加载提前渲染好并带有数据的 DOM,完成服务端渲染,有助于搜索引擎的抓取。

注意事项:

  1. 由于在客户端创建实例化之前加载,所以不能使用 this,钩子提供一个参数,可以获取上下文对象({isDev, route, store, env, params, query, req, res, redirect, error}等),从而做一些简单操作。
  2. 只能在路由页面组件中使用(每次加载页面都会调用),在自定义组件中无效。
  3. 返回的数据最终将与 data 数据合并,为了保证不发生页面渲染错误,返回的键应事先在 data 里声明好(如果 template 中没有使用所需属性,则并不必声明)。
  4. 钩子在路由转换期间解析,所以在 return 之前会一直等待内部逻辑处理,阻止页面加载。如果要抛出异常,可以使用参数提供的 error 方法。

使用方式 (Javascript)

按照官网说明 asyncData 有三种使用方式,
使用示例:

  • 返回 Promise 对象的方式

export default {
  asyncData({ params }) {
    return axios.get(`//my-api/posts/${params.id}`).then(res => {
      return { title: res.data.title };
    });
  }
};
  • 使用 async/await 的方式

export default {
  async asyncData({ params }) {
    const { data } = await axios.get(`//my-api/posts/${params.id}`);
    return { title: data.title };
  }
};
  • 使用回调函数的方式(v2.12 弃用)

export default {
  asyncData({ params }, callback) {
    // asyncData提供两个参数(已弃用)
    axios.get(`//my-api/posts/${params.id}`).then(res => {
      callback(null, { title: res.data.title });
    });
  }
};

使用方式 (Typescript)

Nuxt 的 ts 版组件,有三种构建风格,
使用示例:

  • 选项式 API

export default Vue.extend({
  // async/await方式
  async asyncData({ params }) {
    const { data } = await axios.get(`//my-api/posts/${params.id}`);
    return { title: data.title };
  }

  // Promise方式
  /* asyncData({ params }) {
    return axios.get(`//my-api/posts/${params.id}`).then(res => {
      return { title: res.data.title }
    })
  }, */
});
  • 类式组件

    类式组件应在装饰器内传入该方法,而不是在 Class 内使用。

import { Component, Vue } from "vue-property-decorator";

@Component({
  async asyncData({ params }) {
    const { data } = await axios.get(`//my-api/posts/${params.id}`);
    return { title: data.title };
  }
})
export default class PageIndex extends Vue {
  title: string;
}
  • 组合式 API(v3.0 以上)

import { defineComponent, ref } from "@vue/composition-api";
import { useAsyncData } from "#app";

export default defineComponent({
  async setup() {
    const { data } = await useAsyncData("count", () => $fetch("/api/count"));
    return {
      title: data.title
    };
  }
});

fetch

简介

旧版本的 fetch 在组件实例化之前运行,无法使用 this,如同 asyncData,提供了可查询长下文的参数,且亦只能在页面级组件中使用,并且只能通过上下文参数操作 store 状态的数据,而不能设置或合并 data 数据。

注:由于 fetch 钩子的功能在 nuxt v2.12 以上版本作了较大调整,所以下文只记录新的使用方式。

fetch 用来在组件加载时预先提取数据,运行于组件实例创建之后(created)页面渲染完成之前(mounted),并且可以用于任何组件(包括路由页面或自定义组件)和随时通过$fetch 方法主动更新数据。

使用方式

默认选项式组件:

export default {
  fetchOnServer: false, //可以通过内置的fetchOnServer属性,来关闭服务端fetch行为。
  async fetch() {
    const { data } = await axios.get(
      `//my-api/posts/${this.$route.params.id}`
    );
    this.title = data.title;
  }
};

Typescript 类式组件:

import { Component, Vue } from "vue-property-decorator";

@Component
export default class PageBarIndex extends Vue {
  async fetch(this: PageBarIndex) {
    const { data } = await axios.get(
      `//my-api/posts/${this.$route.params.id}`
    );
    this.title = data.title;
  }
}

asyncData 和 fetch 的区别

  • 组件限制
    • asyncData 仅限于页面级组件。
    • fetch 可用于任意组件。
  • 获取上下文
    • asyncData 不可以使用 this,只能通过回调参数获取上下文对象。
    • fetch 可以使用 this。
  • 数据操作
    • asyncData 通过 return 合并 data 数据。
    • fetch 可以使用 this 直接修改赋值。
  • 调用时机
    • asyncData 只在页面创建前调用。
    • fetch 在页面实例创建后调用,并可以通过$fetch 方法随时触发,$fetchState.timestam 属性可以获取最后一次触发的时间戳。
  • 错误处理
    • asyncData 通过 error 参数抛出错误,但并不会在页面显示异常。
    • fetch 可以使用 throw new Error()来抛出异常,在页面调用$fetchState.error 方法获取异常状态。
  • 页面渲染
    • asyncData 在页面创建前填充数据。
    • fetch 可通过 fetchOnServer 属性设置是否允许在服务端获取数据,设置为 false 将可以在渲染数据时通过$fetchState.pendinding 获取加载状态。

生命周期示意图

image