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