2024-11-05|閱讀時間 ‧ 約 0 分鐘

EP59 - 組件API的問與答

Composition API FAQ,喔喔喔!問與答耶~
快來看看有什麼我內心的疑惑也有在裡頭~
但我都是太新手的疑惑居多 www
提示:本常見問題解答假設您對 Vue 有先前的經驗,特別是對於主要使用 Options API 的 Vue 2 版本的經驗。

什麼是 Composition API? - What is Composition API?

Composition API 是一組 API,允許我們使用導入的函數來編寫 Vue 組件,而不是宣告選項。它是一個總稱,涵蓋以下幾種 API:

  1. 反應性 API:例如 ref() 和 reactive(),允許我們直接創建反應性狀態、計算屬性和監視器。
  2. 生命週期鉤子:例如 onMounted() 和 onUnmounted(),允許我們以程式方式掛鉤到組件的生命週期中。
  3. 依賴注入:即 provide() 和 inject(),允許我們在使用反應性 API 時利用 Vue 的依賴注入系統。

Composition API 是 Vue 3 和 Vue 2.7 的內建功能。對於舊的 Vue 2 版本,可以使用官方維護的 @vue/composition-api 插件。在 Vue 3 中,它主要與單文件組件中的 <script setup> 語法一起使用。以下是一個使用 Composition API 的基本範例:

<script setup>
import { ref, onMounted } from 'vue'

// 反應性狀態
const count = ref(0)

// 修改狀態並觸發更新的函數
function increment() {
count.value++
}

// 生命週期鉤子
onMounted(() => {
console.log(`The initial count is ${count.value}.`)
})
</script>

<template>
<button @click="increment">Count is: {{ count }}</button>
</template>

儘管 Composition API 的風格基於函數組合,它並不是函數式編程。Composition API 基於 Vue 的可變、細粒度的反應性範式,而函數式編程則強調不可變性。

為什麼要使用 Composition API? - Why Composition API?

更好的邏輯重用 - Better Logic Reuse

Composition API 的主要優勢在於它能以可組合函數的形式實現乾淨、高效的邏輯重用。它解決了 Options API 的主要邏輯重用機制(混入)的所有缺點

Composition API 的邏輯重用能力促成了一些令人印象深刻的社群專案,如 VueUse,一個不斷增長的可組合工具集。此外,它還為將有狀態的第三方服務或庫(如不可變數據狀態機RxJS)輕鬆整合到 Vue 的反應性系統中提供了一個乾淨的機制。

更靈活的代碼組織 - More Flexible Code Organization

許多用戶喜歡我們使用 Options API 來編寫有組織的代碼:一切都根據其所屬的選項有其特定的位置。然而,當單個組件的邏輯超過一定的複雜度門檻時,Options API 就會帶來嚴重的限制。這種限制在需要處理多個邏輯關注點的組件中特別突出,我們在許多生產中的 Vue 2 應用中親眼目睹了這一點。

以 Vue CLI 的 GUI 中的資料夾瀏覽器組件為例:此組件負責以下邏輯關注點:

  • 跟蹤當前資料夾狀態並顯示其內容
  • 處理資料夾導航(打開、關閉、刷新...)
  • 處理新資料夾的創建
  • 切換顯示僅收藏資料夾
  • 切換顯示隱藏資料夾
  • 處理當前工作目錄變更

該組件的原始版本是使用 Options API 編寫的。如果我們根據邏輯關注點為每行代碼分配一個顏色,它看起來是這樣的:

注意,處理相同邏輯關注點的代碼被迫分散在不同的選項中,位於文件的不同部分。在一個幾百行長的組件中,理解和導航單一的邏輯關注點需要不斷上下滾動文件,使得這個過程比應有的難得多。此外,如果我們打算將某個邏輯關注點提取為可重用的工具,從文件的不同部分找到並提取正確的代碼片段需要不少工作。

以下是同一組件在重構為 Composition API 前後的對比:

注意,現在與相同邏輯關注點相關的代碼可以組合在一起:在處理特定邏輯關注點時,我們不再需要在不同的選項塊之間跳轉。此外,我們現在可以輕鬆地將一組代碼移動到外部文件,因為我們不再需要為了提取它們而重新安排代碼。這種減少重構摩擦的特性對大型代碼庫的長期可維護性至關重要。

更好的類型推斷 - Better Type Inference

近年來,越來越多的前端開發者採用 TypeScript,因為它有助於我們編寫更健壯的代碼,讓我們更有信心地進行更改,並通過 IDE 支持提供良好的開發體驗。然而,最初在 2013 年設計的 Options API 沒有考慮到類型推斷。我們必須實現一些極其複雜的類型體操來使類型推斷與 Options API 一起工作。即使做了這麼多努力,Options API 的類型推斷在面對混入和依賴注入時仍可能崩潰。

這導致許多希望與 TS 一起使用 Vue 的開發者傾向於使用由 vue-class-component 提供支持的 Class API。然而,基於類的 API 嚴重依賴於 ES 裝飾器,這是一個在 2019 年 Vue 3 開發時僅處於第 2 階段提案的語言功能。我們認為基於一個不穩定的提案來設計官方 API 風險太大。從那時起,裝飾器提案經歷了又一次徹底改革,並在 2022 年最終達到了第 3 階段。此外,基於類的 API 在邏輯重用和組織方面也有類似於 Options API 的限制。

相比之下,Composition API 主要使用普通變量和函數,這些都是自然類型友好的。使用 Composition API 編寫的代碼可以享受完整的類型推斷,幾乎不需要手動類型提示。大多數情況下,Composition API 代碼在 TypeScript 和普通 JavaScript 中看起來幾乎相同。這也使得普通 JavaScript 用戶可以受益於部分類型推斷。

更小的生產包和更少的開銷 - Smaller Production Bundle and Less Overhead

使用 Composition API 和 <script setup> 編寫的代碼比等效的 Options API 更高效且更適合壓縮。這是因為 <script setup> 組件中的模板被編譯為在 <script setup> 代碼的相同作用域內內聯的函數。與從 this 訪問屬性不同,編譯的模板代碼可以直接訪問在 <script setup> 中宣告的變量,而中間沒有實例代理。這也導致更好的壓縮效果,因為所有變量名稱都可以安全地縮短。

與 Options API 的關係 - Relationship with Options API

取捨 - Trade-offs

有些從 Options API 過渡到 Composition API 的用戶發現他們的 Composition API 代碼組織性較差,並認為 Composition API 在代碼組織方面「更糟糕」。我們建議這些用戶從不同的角度來看待這個問題。

確實,Composition API 不再提供「護欄」來引導您將代碼放入各自的框架中。相應地,您可以像編寫普通 JavaScript 一樣撰寫組件代碼。這意味著您可以並且應該將任何代碼組織最佳實踐應用於您的 Composition API 代碼,就像編寫普通 JavaScript 一樣。如果您能寫出組織良好的 JavaScript,您也應該能寫出組織良好的 Composition API 代碼。

Options API 確實允許您在撰寫組件代碼時「思考更少」,這也是為什麼許多用戶喜歡它。然而,在減少思維負擔的同時,它也將您鎖定在預設的代碼組織模式中,沒有退出機制,這可能使在大型項目中進行重構或提高代碼質量變得困難。就這方面而言,Composition API 提供了更好的長期可擴展性。

Composition API 覆蓋所有用例嗎? - Does Composition API cover all use cases?

在有狀態邏輯方面,答案是肯定的。使用 Composition API 時,只有幾個選項仍然需要:propsemitsnameinheritAttrs

小提示:自 3.3 版本起,您可以直接在 <script setup> 中使用 defineOptions 設置組件名或 inheritAttrs 屬性。

如果您打算專門使用 Composition API(以及上述選項),您可以通過編譯時標誌刪除 Vue 中的 Options API 相關代碼,從而減少幾個 KB 的生產包大小。請注意,這也會影響您的依賴項中的 Vue 組件。

可以在同一個組件中使用兩種 API 嗎? - Can I use both APIs in the same component?

可以。您可以通過 setup() 選項在 Options API 組件中使用 Composition API。

然而,我們只建議在需要與使用 Composition API 編寫的新功能/外部庫集成的現有 Options API 代碼庫中這樣做。

Options API 會被棄用嗎? - Will Options API be deprecated?

不,我們沒有這樣的計劃。Options API 是 Vue 的一個重要組成部分,許多開發者都喜歡它。我們也意識到 Composition API 的許多優點僅在大型項目中顯現,而 Options API 在許多低到中等複雜度的場景中仍然是穩健的選擇。

與 Class API 的關係 - Relationship with Class API

我們不再建議在 Vue 3 中使用 Class API,因為 Composition API 提供了出色的 TypeScript 集成以及額外的邏輯重用和代碼組織優勢。

與 React Hooks 的比較 - Comparison with React Hooks

Composition API 提供了與 React Hooks 相同級別的邏輯組合能力,但有一些重要的區別。

React Hooks 在每次組件更新時都會重複調用,這會導致許多容易混淆的情況,甚至連有經驗的 React 開發者也會困惑。這也會導致性能優化問題,嚴重影響開發體驗。以下是一些例子:

  • Hooks 對調用順序敏感,不能是條件式的。
  • React 組件中聲明的變量可能會被 Hook 閉包捕獲,並在開發者未能傳遞正確的依賴數組時變得「過時」。這使得 React 開發者依賴 ESLint 規則來確保傳遞了正確的依賴。然而,該規則通常不夠智能,過度補償正確性,導致不必要的無效化,並在遇到邊緣情況時頭痛。
  • 昂貴的計算需要使用 useMemo,這又需要手動傳遞正確的依賴數組。
  • 傳遞給子組件的事件處理程序默認會導致不必要的子更新,並需要顯式使用 useCallback 作為優化。這幾乎總是需要的,並且再次需要正確的依賴數組。忽視這一點會導致默認情況下過度渲染的應用程序,並可能在未意識到的情況下造成性能問題。
  • 過時的閉包問題,加上 Concurrent 特性,使得推理何時運行一段 hooks 代碼變得困難,並使得處理應在渲染之間持久化的可變狀態(通過 useRef)變得繁瑣。
注意:一些與記憶化相關的上述問題可以通過即將推出的 React 編譯器解決。

相比之下,Vue Composition API:

  • 只調用一次 setup()<script setup> 代碼。這使得代碼更符合 JavaScript 的直觀使用,因為不會有過時的閉包需要擔心。Composition API 調用也不對調用順序敏感,可以是條件式的。
  • Vue 的運行時響應系統自動收集在計算屬性和監聽器中使用的響應依賴,因此無需手動聲明依賴。
  • 無需手動緩存回調函數以避免不必要的子更新。一般來說,Vue 的細粒度響應系統確保子組件只在需要時更新。對 Vue 開發者來說,手動的子更新優化幾乎不是一個問題。

我們承認 React Hooks 的創意,並且它是 Composition API 的一個主要靈感來源。然而,這些設計中提到的問題確實存在,我們注意到 Vue 的響應模型恰好提供了一種解決這些問題的方法。

好像對組件API有更多瞭解了!!!
晚安摟~早點睡覺!!!
分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.