前言
如果是經驗不夠多的同志在學習Vue的時候,在最開始會接觸到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。請問各位同志,Vue3 是不是可以適合開發大型應用了呢?
總結
將同一個邏輯關注點相關程式碼收集在一起,在處理單個邏輯關注點時,我們必須不斷地“跳轉”相關程式碼的選項塊。使得開發人員更容易閱讀和理解這些程式碼,這正是組合式 API 要解決的問題。
組合式 API 也導致以往的寫法不相同,所以各位同志還是需要花時間去適應一段時間。