其實你不一定要在 onMounted 取 API

鱈魚-avatar-img
發佈於Vue
更新 發佈閱讀 9 分鐘
鱈魚的魚缸搬家了!新家文章有重新修訂,歡迎來新家看看喔。(´▽`ʃ♡ƪ)
寫扣的鱈魚

寫扣的鱈魚

大家好,我是鱈魚。(。・∀・)ノ゙


最近看到大家討論取得 API 時機,有許多人都提到「一定要」或者「習慣」,在 onMounted 這個 hook 內呼叫 API 取得資料。


其實這也沒不好,但是也沒什麼好處就是了。(。・ω・。)


讓我們來思考一下下,有關於 Vue 取得 API 資料這檔事。(不會轉生,也沒有史萊姆

「一定要」在 onMounted

有人說「一定要」是因為不這麼做會壞掉,這個可以從 2 個部分來看。


首先是 onMounted 這個 hook 是甚麼?讓我們看看官網的定義:

Registers a callback to be called after the component has been mounted.

意思就是「註冊一個會在元件安裝完成後被呼叫的 callback」。


甚麼意思呢?也就是他和有沒有資料一點關係都沒有。換句話說 onMounted 沒辦法幫你保證有資料、template 不會壞,從此天下太平,再也不用加班,。(´。_。`)


所以就牽扯到了第二部分:為甚麼會壞掉?


馬上取會壞,onMounted 取就不會壞,這表示你的資料可能和 DOM 或元件發生耦合,這其實不是好現象,不但違反了資料驅動的概念還埋了隱形的翅膀…地雷。


具體原因可能如下:

  • API 參數耦合了某個 DOM 的資料,導致「沒有在 onMounted 取值」等於「對 undefined 動手動腳」,當然就壞掉惹。(〃` 3′〃)
  • API 參數或操作耦合了某個子元件,而 Vue 的 onMounted 會保證子元件都 onMounted 完後,自己的 onMounted 才會觸發,導致 onMounted 取才沒事。


所以總結來說,所謂的「壞掉」很有可能只是資料流沒考慮 undefined 的情境。


(可能啦,我巫力不足,只能通靈到這裡惹。 ╮(╯▽╰)╭)


如果有使用 TypeScript 就很少會出現這類問題了,因為 TypeScript 會先不開心、滿江紅給你看。ᕦ(ò_óˇ)ᕤ

「習慣」在 onMounted

習慣上可能會這樣寫:

<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { getUser, User } from './api'

const user = ref<User>();

onMounted(async () => {
try {
user.value = await getUser();
} catch (error) {
console.error('QQ');
}
});
</script>

<template>
<h1>Classic</h1>
<div>
user: {{ user?.name }}
</div>
</template>


考慮讀取狀態則可能再加個 loading:

<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { getUser, User } from './api'

const user = ref<User>();
const isLoading = ref(false);

onMounted(async () => {
try {
isLoading.value = true;
user.value = await getUser();
} catch (error) {
console.error('QQ');
} finally {
isLoading.value = false;
}
});
</script>

<template>
<h1>Classic</h1>
<div v-if="isLoading">
資料讀取中...(~﹃~)~zZ
</div>
<div v-else>
user: {{ user?.name }}
</div>
</template>


剛剛說了,其實不用在 onMounted 才取資料,早一點取也行,所以可以變成這樣:

<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { getUser, User } from './api'

const user = ref<User>();
const isLoading = ref(true);

getUser().then((data) => {
user.value = data;
}).catch(() => {
console.error('QQ');
}).finally(() => {
isLoading.value = false;
});
</script>
...


路人:「這樣真的有比較好嗎?」

鱈魚:「當然沒有。(≧∇≦)ノ」

路人:(抄起球棒)

鱈魚:「冷靜冷靜,還沒說完啊。(っ °Д °;)っ」


來點 Composition

讓我們回想一下 Vue 3 的 Composition API 精神,一但要取得資料變多後,仔細觀察可以發現「資料、狀態(isLoading)、取資料的 function」會重複出現。


讓我們抽離、重組一下,新增一個檔案。

  • useAsyncData.ts
import { ref } from 'vue';

interface UseAsyncDataParam<Data> {
executor: () => Promise<Data>;
onError?: (error: unknown) => void;
}

export function useAsyncData<Data>(param: UseAsyncDataParam<Data>) {
const data = ref<Data>();
const isLoading = ref(true);

param.executor().then((result) => {
data.value = result;
}).catch((error) => {
param.onError?.(error);
}).finally(() => {
isLoading.value = false;
});

return {
data,
isLoading,
execute: param.executor,
}
}


(寫過 Nuxt 的朋友們一定會有熟悉的感覺。(. ❛ ᴗ ❛.))


現在讓我們用這個 useAsyncData 改寫一下剛剛的例子看看。

<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { getUser, User } from './api'
import { useAsyncData } from './useAsyncData'

const {
data: user,
isLoading,
} = useAsyncData({
executor: () => getUser(),
onError() {
console.error('QQ');
},
});
</script>

<template>
<h1>Composable</h1>
<div v-if="isLoading">
資料讀取中...(~﹃~)~zZ
</div>
<div v-else>
user: {{ user?.name }}
</div>
</template>

就算有多個狀態要取得也變得更好組織程式碼了,是不是看起來乾淨許多呢?


恭喜我們重複造了 Nuxt 的 useAsyncData 與 VueUse 的 useAsyncState 的輪子了!

★,°:.ヽ(✿゚▽゚)ノ$:.°★


沒錯,雖然目前這個 useAsyncData 的功能很簡陋,有很多需要改進的部分,但是這就是上述兩個 API 的基礎精神。


不過 Nuxt 還包含了 SSR 行為,所以更加複雜,推薦大家可以看看 VueUse useAsyncState 的文件原始碼,一定可以獲益良多。


文章到此結束了,感謝您的閱讀,以上範例程式碼可以在此取得

有其他想法請不吝告訴我,鱈魚感謝您!(o゜▽゜)o☆

留言
avatar-img
鱈魚的魚缸
17會員
14內容數
各種鱈魚滾鍵盤的雜紀
鱈魚的魚缸的其他內容
2024/07/25
先前提到 Quasar 的 Dialog Plugin 很好用,再讓我補充一個用法。
Thumbnail
2024/07/25
先前提到 Quasar 的 Dialog Plugin 很好用,再讓我補充一個用法。
Thumbnail
2024/07/15
Quasar Dialog 的 Invoking custom component 很好用,但是有些困擾的地方,一起來看看有甚麼辦法吧。
Thumbnail
2024/07/15
Quasar Dialog 的 Invoking custom component 很好用,但是有些困擾的地方,一起來看看有甚麼辦法吧。
Thumbnail
2024/07/10
切換頁面卡卡有很多種原因,這裡舉的例子只針對元件太大的情境。 除了想辦法拆分外,還有一個方法就是利用 Vue 的 Async Component。
Thumbnail
2024/07/10
切換頁面卡卡有很多種原因,這裡舉的例子只針對元件太大的情境。 除了想辦法拆分外,還有一個方法就是利用 Vue 的 Async Component。
Thumbnail
看更多
你可能也想看
Thumbnail
賽勒布倫尼科夫以流亡處境回望蘇聯電影導演帕拉贊諾夫的舞台作品,以十段寓言式殘篇,重新拼貼記憶、暴力與美學,並將審查、政治犯、戰爭陰影與「形式即政治」的劇場傳統推到台前。本文聚焦於《傳奇:帕拉贊諾夫的十段殘篇》的舞台美術、音樂與多重扮演策略,嘗試解析極權底下不可言說之事,將如何成為可被觀看的公共發聲。
Thumbnail
賽勒布倫尼科夫以流亡處境回望蘇聯電影導演帕拉贊諾夫的舞台作品,以十段寓言式殘篇,重新拼貼記憶、暴力與美學,並將審查、政治犯、戰爭陰影與「形式即政治」的劇場傳統推到台前。本文聚焦於《傳奇:帕拉贊諾夫的十段殘篇》的舞台美術、音樂與多重扮演策略,嘗試解析極權底下不可言說之事,將如何成為可被觀看的公共發聲。
Thumbnail
柏林劇團在 2026 北藝嚴選,再次帶來由布萊希特改編的經典劇目《三便士歌劇》(The Threepenny Opera),導演巴里・柯斯基以舞台結構與舞台調度,重新向「疏離」進行提問。本文將從觀眾慾望作為戲劇內核,藉由沉浸與疏離的辯證,解析此作如何再次照見觀眾自身的位置。
Thumbnail
柏林劇團在 2026 北藝嚴選,再次帶來由布萊希特改編的經典劇目《三便士歌劇》(The Threepenny Opera),導演巴里・柯斯基以舞台結構與舞台調度,重新向「疏離」進行提問。本文將從觀眾慾望作為戲劇內核,藉由沉浸與疏離的辯證,解析此作如何再次照見觀眾自身的位置。
Thumbnail
本文深入解析臺灣劇團「晃晃跨幅町」對易卜生經典劇作《海妲.蓋柏樂》的詮釋,從劇本歷史、聲響與舞臺設計,到演員的主體創作方法,探討此版本如何讓經典劇作在當代劇場語境下煥發新生,滿足現代觀眾的觀看慾望。
Thumbnail
本文深入解析臺灣劇團「晃晃跨幅町」對易卜生經典劇作《海妲.蓋柏樂》的詮釋,從劇本歷史、聲響與舞臺設計,到演員的主體創作方法,探討此版本如何讓經典劇作在當代劇場語境下煥發新生,滿足現代觀眾的觀看慾望。
Thumbnail
《轉轉生》為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,融合舞蹈、音樂、時尚和視覺藝術,透過身體、服裝與群舞結構,回應殖民歷史、城市經驗與祖靈記憶的交錯。本文將從服裝設計、身體語彙與「輪迴」的「誕生—死亡—重生」結構出發,分析《轉轉生》如何以當代目光,形塑去殖民視角的奈及利亞歷史。
Thumbnail
《轉轉生》為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,融合舞蹈、音樂、時尚和視覺藝術,透過身體、服裝與群舞結構,回應殖民歷史、城市經驗與祖靈記憶的交錯。本文將從服裝設計、身體語彙與「輪迴」的「誕生—死亡—重生」結構出發,分析《轉轉生》如何以當代目光,形塑去殖民視角的奈及利亞歷史。
Thumbnail
各位使用 Vue.js 開發的小夥伴們,你們都怎麼實作父子層組件資料的雙向綁定呢?如果你還在寫 prop + emit 的話,不妨進來看看吧。
Thumbnail
各位使用 Vue.js 開發的小夥伴們,你們都怎麼實作父子層組件資料的雙向綁定呢?如果你還在寫 prop + emit 的話,不妨進來看看吧。
Thumbnail
大家好,我是鱈魚。(。・∀・)ノ゙ 最近看到大家討論取得 API 時機,有許多人都提到「一定要」或者「習慣」,在 onMounted 這個 hook 內呼叫 API 取得資料。 其實這也沒不好,但是也沒什麼好處就是了。(。・ω・。)
Thumbnail
大家好,我是鱈魚。(。・∀・)ノ゙ 最近看到大家討論取得 API 時機,有許多人都提到「一定要」或者「習慣」,在 onMounted 這個 hook 內呼叫 API 取得資料。 其實這也沒不好,但是也沒什麼好處就是了。(。・ω・。)
Thumbnail
如果前人已經走出一條最佳路徑,我們只顧著欣賞也會到山頂 關注點的改變 一個好的架構都會希望讓開發者能專注在”業務邏輯”的實現,可以提高專案的開發效率、減少開發者非關業務邏輯的事情而煩惱。例如: 開發者A: 請問元件的對話窗如何在確認時控制關閉或開啟狀態? 這個實際案例是架構師認為對話窗的動作
Thumbnail
如果前人已經走出一條最佳路徑,我們只顧著欣賞也會到山頂 關注點的改變 一個好的架構都會希望讓開發者能專注在”業務邏輯”的實現,可以提高專案的開發效率、減少開發者非關業務邏輯的事情而煩惱。例如: 開發者A: 請問元件的對話窗如何在確認時控制關閉或開啟狀態? 這個實際案例是架構師認為對話窗的動作
Thumbnail
Vue3 筆記,指令進階篇
Thumbnail
Vue3 筆記,指令進階篇
Thumbnail
Vue3 學習筆記,用 Pinia 管理資料與邏輯
Thumbnail
Vue3 學習筆記,用 Pinia 管理資料與邏輯
Thumbnail
Vue3 學習筆記,元件與資料傳遞篇
Thumbnail
Vue3 學習筆記,元件與資料傳遞篇
Thumbnail
Vue3 學習筆記,專案建立與基礎響應式篇
Thumbnail
Vue3 學習筆記,專案建立與基礎響應式篇
Thumbnail
v-bind v-bind 可以讓 template 內的標籤去綁定 script 內定義的變數,舉個例子 可以改寫成這樣 最後效果是一樣的,在標籤內 v-bind 可以簡寫成 : v-model 上一篇已經提到了,就是可以透過網頁上的操作去改變資料的值,比方說表單、輸入欄等等。 v-for 迴圈,
Thumbnail
v-bind v-bind 可以讓 template 內的標籤去綁定 script 內定義的變數,舉個例子 可以改寫成這樣 最後效果是一樣的,在標籤內 v-bind 可以簡寫成 : v-model 上一篇已經提到了,就是可以透過網頁上的操作去改變資料的值,比方說表單、輸入欄等等。 v-for 迴圈,
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News