其實你不一定要在 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內容數
各種鱈魚滾鍵盤的雜紀
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
鱈魚的魚缸 的其他內容
pipe 代表函數式程式設計中的概念,利用多個功能結合在一起,資料依序通過每個功能進行處理。文章中介紹了 pipe 的優點、兩個等效的程式碼比較以及 remeda 套件的使用。詳細介紹了使用 pipe 的好處,並提供了多個相關的例子,展示了 pipe 可讀性的提升。
pipe 代表函數式程式設計中的概念,利用多個功能結合在一起,資料依序通過每個功能進行處理。文章中介紹了 pipe 的優點、兩個等效的程式碼比較以及 remeda 套件的使用。詳細介紹了使用 pipe 的好處,並提供了多個相關的例子,展示了 pipe 可讀性的提升。
你可能也想看
Google News 追蹤
這天他正在默默釣魚!
Thumbnail
我只釣到雞泡魚,🥹🐟 但別人釣到墨魚啊!😭🦑
前陣子開始養鬥魚,紀錄一些網路上的相關資訊供有興趣者參考。
Thumbnail
先前幾篇筆記介紹了網路請求,瀏覽器儲存資料的方式,那麼實務上,前端最常需要發送網路請求的時候,就是透過呼叫 API,去向後端工程師發送/請求資料,所以今天來記錄什麼是 API吧!
這天他正在默默釣魚!
Thumbnail
我只釣到雞泡魚,🥹🐟 但別人釣到墨魚啊!😭🦑
前陣子開始養鬥魚,紀錄一些網路上的相關資訊供有興趣者參考。
Thumbnail
先前幾篇筆記介紹了網路請求,瀏覽器儲存資料的方式,那麼實務上,前端最常需要發送網路請求的時候,就是透過呼叫 API,去向後端工程師發送/請求資料,所以今天來記錄什麼是 API吧!