前言
在學習Vue的時候,最開始都是會從選項式API開始學起,到了后邊官方給出了 Vue3 的新方式 —— 組合式API。相信會有不少人跟我一樣,第一次聽到新的名詞時陷入了困擾。那么,什么是組合式API呢?
選項式API的壞處
代碼碎片化
通常在維護和開發一個組件時,分為 data、methods、computed、props 等。假如有一些業務在選項 API 的 data、methods、computed 中進行操作。把要關注的相同視角分別用不同顏色的框子框起來,發現我們的關注點被拆分成了這樣:

先不說大組件的關注點會被拆分成怎么樣,就單純這一個很簡單的演示就能夠讓各位同志體會到選項式 API 的壞處了。當我們的組件開始變得更大時,邏輯關注點的列表也會增長。如果你是一個軍隊的指揮官,你會選擇把戰線拉得很長嗎?費時費力,后勤補給也跟不上。
這種碎片化使得理解和維護復雜組件變得困難,選項的分離掩蓋了潛在的邏輯問題。此外,在處理單個邏輯關注點時,我們必須不斷地“跳轉”相關代碼的選項塊。
邏輯不復用
選項式API使代碼變得碎片化,曾經我想過把一段多次使用到的業務代碼抽離到一個單獨的 js 文件里。我遇到過一些困擾的小問題。首先,在 data 選項聲明的變量才是響應式數據。其次,在 methods 選項聲明的函數才可以操控組件里的響應式數據。這是下文分析選項式API邏輯不復用時的重要前提條件。
在 demo.js 文件里,我定義了一個 a 變量,calc 函數改變 a 的值:
export let a = 'foo'
export function calc() { a = a + 'bar' }
對於這樣的抽離方式,在使用的時候,依舊是需要把變量導入到 data 選項,使其成為響應式數據;函數導入到 methods 選項。
import { a, calc } from './demo.js'
export default {
data() { return { a } },
methods: { _calc() { calc() } }
}
由於 demo.js 文件里的函數操作的是 demo.js 文件里的變量 a ,而不是組件中響應式數據 a。導致我點擊了按鈕之后頁面未作出任何反應。
解決方法是,calc 函數接受一個形參,然后再返回。當然可以!這只是一個簡單的字符拼接而已。但是,這不是非常直接的辦法,要經歷一些曲折,同樣會導致代碼難讀懂的問題。
官方提供的解決方案是混入,而混入還是在寫選項API。不再選項API!不再選項API!不再選項API!,因為不符合期望。讀到這里,想必知道了選項式API的壞處了。
一句話總結選項式API的壞處就是:代碼碎片化、邏輯不復用
組合式API的好處
代碼集中化
為什么組合式API就可以讓代碼不碎片化呢?因為組合式API的組合就在於它把變量、函數集中在一起,減少分離掩蓋的潛在的邏輯問題,不在“跳轉”相關代碼的選項塊。
所以,是如何集中化的呢?因為 Vue3 要實現代碼集中化,所以,Vue3 的許多選項都抽離成為了一個個模塊(這是我的猜想,因為每次用到什么必須從 vue 模塊導入什么)。
組合式API就是一個 setup
函數,我們的所有代碼全部都要寫在這里面。
import { ref } from 'vue'
export default {
setup() {
let a = ref('foo')
function calcA() { a.value = a.value + 'bar' }
let b = ref('bar')
function calcB() { b.value = b.value + 'foo' }
let c = ref('hello')
function calcC() { c.value = c.value + 'world' }
let d = ref('world')
function calcD() { d.value = d.value + 'hello' }
}
}
現在,我們的關注點會被集中化,用圖表示就是:

不知道各位是否有感受到這種變化,筆者已經感受到組合式API的強大了。
邏輯高復用
還記得第一章第二小節說到的問題嗎?Vue3 的許多選項都抽離成為了一個個模塊,所以我們可以在一個單獨的 js 聲明響應式數據了,就是利用 ref
函數來操作的。
我們新建一個 demo2.js 文件,首先引入 vue 模塊中的 ref 函數,用於聲明一個響應式數據:
import { ref } from 'vue'
export let a = ref('foo')
export function calc() { a.value = a.value + 'bar' }
然后我們在其他組件中使用:
import { a, calc } from './demo2.js'
export default {
setup() {
return { a, calc } // 這里需要導出a和calc
}
}
由於在 demo2.js 的 calc 函數操作的已經是一個響應式數據了,所以,組件一旦用到了這個模塊中的東西,它都會反映到頁面中。
大功告成,這得益於 Vue3 的一大進步啊!現在我們寫代碼可以寫得非常舒服了。再加上 Vue3 是 TS 重構的,按道理來說是非常支持 TS 的寫法的,前提是你的項目支持 TS。
總結
將同一個邏輯關注點相關代碼收集在一起,在處理單個邏輯關注點時,我們必須不斷地“跳轉”相關代碼的選項塊。使得開發人員更容易閱讀和理解這些代碼,這正是組合式 API 要解決的問題。