NuxtJS的 AsyncData 和 Fetch 使用詳解

餘以為發表於2021-12-09

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(`https://my-api/posts/${params.id}`).then(res => {
      return { title: res.data.title };
    });
  }
};
  • 使用 async/await 的方式

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

export default {
  asyncData({ params }, callback) {
    // asyncData提供兩個引數(已棄用)
    axios.get(`https://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(`https://my-api/posts/${params.id}`);
    return { title: data.title };
  }

  // Promise方式
  /* asyncData({ params }) {
    return axios.get(`https://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(`https://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(
      `https://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(
      `https://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

相關文章