跳轉到內容

Composition API常見問題解答

提示

此常見問題解答假定您具備Vue經驗 - 尤其是在主要使用Options API的情況下使用Vue 2的經驗。

什麼是Composition API?

Composition API是一組API,允許我們使用匯入的函式而不是宣告選項來編寫Vue元件。這是一個總稱,包括以下API

  • 響應式API,例如ref()reactive(),允許我們直接建立響應式狀態、計算狀態和監視器。

  • 生命週期鉤子,例如onMounted()onUnmounted(),允許我們以程式設計方式掛鉤到元件生命週期。

  • 依賴注入,即provide()inject(),允許我們在使用響應式API的同時利用Vue的依賴注入系統。

Composition API是Vue 3和Vue 2.7的內建功能。對於較老的Vue 2版本,請使用官方維護的@vue/composition-api外掛。在Vue 3中,它也主要用於與單檔案元件中的<script setup>語法一起使用。以下是一個使用Composition API的元件的基本示例

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

// reactive state
const count = ref(0)

// functions that mutate state and trigger updates
function increment() {
  count.value++
}

// lifecycle hooks
onMounted(() => {
  console.log(`The initial count is ${count.value}.`)
})
</script>

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

儘管基於函式組合的API風格,但Composition API不是函數語言程式設計。Composition API基於Vue的可變、細粒度的響應式正規化,而函數語言程式設計強調不可變性。

如果您想了解如何使用Composition API與Vue結合,您可以透過左側側邊欄頂部的切換將網站級別的API偏好設定為Composition API,然後從頭開始瀏覽指南。

為什麼使用Composition API?

更好的邏輯複用

Composition API 的主要優勢是它能夠以可組合函式的形式實現乾淨的、高效的邏輯複用,詳情請參閱 可組合函式。它解決了 混入(mixins)的所有缺點,混入是 Options API 的主要邏輯複用機制。

Composition API 的邏輯複用能力催生了令人印象深刻的社群專案,如 VueUse,這是一個不斷增長的組合實用工具集合。它還提供了一種乾淨的機制,可以輕鬆地將具有狀態的第三方服務或庫整合到 Vue 的響應性系統中,例如 不可變資料狀態機RxJS

更靈活的程式碼組織

許多使用者喜歡使用 Options API 預設編寫的有組織程式碼:每個部分都有其位置,基於其所屬的選項。然而,當單個元件的邏輯超過一定複雜性閾值時,Options API 會帶來嚴重的限制。這種限制在需要處理多個 邏輯關注點 的元件中尤為突出,我們在許多生產 Vue 2 應用中親身體驗過這一點。

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

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

該元件的 原始版本 是用 Options API 編寫的。如果我們根據每行程式碼處理的邏輯關注點為其著色,這將是這樣

folder component before

請注意,處理相同邏輯關注點的程式碼被迫在不同的選項下分裂,位於檔案的不同部分。在一個數百行長的元件中,理解和導航單個邏輯關注點需要不斷上下滾動檔案,這比應該要困難得多。此外,如果我們打算將邏輯關注點提取為可重用工具,則需要相當多的工作來查詢和從檔案的不同部分提取正確的程式碼片段。

這是相同的元件,在 重構為 Composition API 之前和之後

folder component after

請注意,現在與相同邏輯關注點相關的程式碼可以分組在一起:我們在處理特定邏輯關注點時不再需要在不同選項塊之間跳轉。此外,我們現在可以輕鬆地將一組程式碼移動到外部檔案,因為我們不再需要重新整理程式碼來提取它們。這種減少重構摩擦是大型程式碼庫長期維護的關鍵。

更好的型別推斷

近年來,越來越多的前端開發者開始採用TypeScript,因為它有助於我們編寫更健壯的程式碼,更有信心地進行更改,並提供了IDE支援的卓越開發體驗。然而,最初於2013年構思的Options API,在設計時並未考慮到型別推斷。我們不得不實施一些荒謬複雜的型別體操,以使型別推斷與Options API協同工作。即便付出了所有這些努力,Options API的型別推斷對於混合和依賴注入仍然可能會失敗。

這導致許多希望使用Vue和TS的開發者傾向於使用由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使用者能夠從中受益於部分型別推斷。

更小的生產包和更少的開銷

使用Composition API和<script setup>編寫的程式碼也比Options API等效程式碼更高效、更易於壓縮。這是因為<script setup>元件中的模板被編譯為與<script setup>程式碼相同作用域內的行內函數。與從this屬性訪問不同,編譯後的模板程式碼可以直接訪問<script setup>內部宣告的變數,而不需要例項代理。這也導致更好的壓縮,因為所有變數名都可以安全地縮短。

與Options API的關係

權衡

一些從Options API遷移到Composition API的使用者發現他們的Composition API程式碼組織性較差,並得出結論認為Composition API在程式碼組織方面“更差”。我們建議有這種觀點的使用者從不同角度看待這個問題。

確實,Composition API不再提供引導您將程式碼放入相應桶中的“護欄”。作為交換,您可以像編寫普通JavaScript一樣編寫元件程式碼。這意味著您可以在編寫普通JavaScript時像對待Composition API程式碼一樣應用任何程式碼組織最佳實踐。如果您能編寫有組織的JavaScript,您也應該能夠編寫有組織的Composition API程式碼。

選項API確實允許你在編寫元件程式碼時“思考得更少”,這也是許多使用者喜愛它的原因。然而,在減少心理負擔的同時,它也把你鎖定在規定的程式碼組織模式中,沒有逃脫的出口,這在大型專案中可能會使程式碼重構或提高程式碼質量變得困難。在這方面,組合API提供了更好的長期可擴充套件性。

組合API覆蓋了所有用例嗎?

是的,在狀態邏輯方面。當使用組合API時,只有少數選項可能仍然需要:propsemitsnameinheritAttrs

提示

從3.3版本開始,你可以在<script setup>中直接使用defineOptions來設定元件名稱或inheritAttrs屬性

如果你打算僅使用組合API(以及上面列出的選項),你可以透過一個編譯時標誌來減少生產包的大小,該標誌從Vue中刪除了選項API相關的程式碼。注意這也會影響你的依賴項中的Vue元件。

我可以在同一個元件中使用這兩個API嗎?

是的。你可以在選項API元件中使用setup()選項來使用組合API。

然而,我們只建議這樣做,如果你有一個需要與使用組合API編寫的新功能/外部庫整合的現有選項API程式碼庫。

選項API會被棄用嗎?

不會,我們沒有這樣的計劃。選項API是Vue的一個組成部分,這也是許多開發者喜歡它的原因。我們也意識到,組合API的許多好處只有在大型專案中才會顯現,而選項API仍然是許多低到中等複雜場景的一個可靠選擇。

與類API的關係

鑑於組合API提供了與TypeScript的出色整合以及額外的邏輯複用和程式碼組織優勢,我們不再建議在Vue 3中使用類API。

與React Hooks的比較

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

React Hooks會在元件每次更新時重複呼叫。這產生了一些可能導致經驗豐富的React開發者困惑的注意事項。它還導致了可能導致嚴重影響開發體驗的效能最佳化問題。以下是一些例子

  • Hooks對呼叫順序敏感,不能有條件地呼叫。

  • 在React元件中宣告的變數可能會被hook閉包捕獲,如果開發者未能傳遞正確的依賴陣列,則可能會變成“過時”。這導致React開發者依賴於ESLint規則來確保傳遞了正確的依賴項。然而,該規則通常不夠智慧,過度補償了正確性,導致不必要的無效化和在遇到邊緣情況時的頭痛。

  • 昂貴的計算需要使用useMemo,這又需要手動傳遞正確的依賴陣列。

  • 將事件處理器傳遞給子元件預設會導致不必要的子元件更新,需要顯式使用 useCallback 進行最佳化。這幾乎是必需的,並且還需要正確設定依賴陣列。忽視這一點將導致應用程式預設過度渲染,並且可能在不經意間引發效能問題。

  • 陳舊的閉包問題,結合併發功能,使得難以推斷鉤子程式碼何時執行,並且在使用應該跨渲染持續存在(透過 useRef)的可變狀態時變得繁瑣。

注意:上述與記憶化相關的一些問題可以透過即將推出的 React 編譯器 解決。

相比之下,Vue 組合式API

  • 僅呼叫一次 setup()<script setup> 程式碼。這使得程式碼更好地與慣用JavaScript的使用直覺相匹配,因為無需擔心陳舊的閉包。組合式API呼叫也不受呼叫順序的影響,並且可以進行條件呼叫。

  • Vue的執行時響應式系統會自動收集用於計算屬性和觀察者的響應式依賴項,因此無需手動宣告依賴項。

  • 無需手動快取回撥函式以避免不必要的子元件更新。一般來說,Vue的精細粒度響應式系統確保子元件只在需要時更新。對於Vue開發者來說,手動最佳化子元件更新通常不是問題。

我們承認React Hooks的創造性,它是組合式API的主要靈感來源。然而,上述提到的問題確實存在於其設計中,我們注意到Vue的響應式模型恰好提供了一種繞過這些問題的方法。

組合式API常見問題解答已載入