升級Vue3后,讓人最腦殼疼的應(yīng)該是新的Compostion API語法,他的難點不是語法,而是他提供了全新的組織代碼的思維方式。
我剛從Vue2轉(zhuǎn)到Vue3時,代碼都嚴(yán)格的遵循Compostion API寫法,但是發(fā)現(xiàn)比Option API寫法維護性更差。
踩過的坑
1、按技術(shù)類型劃分代碼
在日常開發(fā)中,前端一般會收到交互稿或設(shè)計稿后開始布局,然后編寫邏輯代碼。在Vue2中,通常做法是響應(yīng)數(shù)據(jù)放到data、邏輯方法放到methods,這樣的做法非常方便,也讓我們很容易組織代碼。
當(dāng)使用vue3的Compostion API時,如果還是用Vue2的形式組織代碼,這不但不會提升代碼質(zhì)量,反而因為缺乏約束而降低可讀性。
我在github隨便找了一段代碼,你覺得這段代碼比Vue2簡潔嗎?
- export default {
- setup () {
- const state = reactive({
- message: '',
- msgList: []
- })
- const router = useRouter()
- let username = ''
- onMounted(() => {
- username = localStorage.getItem('username')
- if (!username) {
- router.push('/login')
- return
- }
- })
- const onSendMessage = () => {
- const { message } = state
- if (!message.trim().length) return
- state.msgList.push({
- id: new Date().getTime(),
- user: username,
- dateTime: new Date().getTime(),
- message: state.message
- })
- state.message = ''
- }
- return {
- ...toRefs(state),
- onSendMessage
- }
- }
- }
實際上我們過于關(guān)注語法層面改變,而忽略官方文檔提到一個詞叫:邏輯關(guān)注點!!!!!!, 邏輯關(guān)注點是指表達同一個業(yè)務(wù)的代碼內(nèi)聚到一起,這也是單一職責(zé)的指導(dǎo)思想,我們內(nèi)聚的不應(yīng)該技術(shù)類型,而是業(yè)務(wù)邏輯,因為觸發(fā)代碼變更的往往是業(yè)務(wù)需求,因此把相同變更理由的代碼放在一起,這才不會導(dǎo)致散彈式修改。
2、過于關(guān)注邏輯復(fù)用
compostion API一個特點是提升邏輯復(fù)用,這是沒有錯的,但是當(dāng)時我有一個錯誤觀點,就是只有復(fù)用的邏輯才應(yīng)該封裝到hook中。
我們還是回到Vue的官方例子,你會發(fā)現(xiàn)他把原來放在一個vue文件的邏輯拆分到composables目錄,目錄下分別定義一個文件,表示不同的邏輯關(guān)注點。
官方文檔地址:https://v3.cn.vuejs.org/guide/composition-api-introduction.html#什么是組合式-api
參考代碼倉庫:https://github.com/barnett617/composition-api-demo/blob/292cc63e2e/src/components/UserRepositoriesV3.vue
這個文件夾的代碼強調(diào)的并不是邏輯復(fù)用,而是邏輯關(guān)注點分離,這也是compostion API最核心要解決的問題,因為應(yīng)用生命周期60%時間都是在維護的,而維護性體現(xiàn)在代碼是否符合單一職責(zé)原則,單一職責(zé)就是把相同的業(yè)務(wù)代碼內(nèi)聚到一個地方。
所以你不要過于糾結(jié)代碼是否需要復(fù)用,應(yīng)用適當(dāng)?shù)娜哂喾炊黾討?yīng)用的維護性,《架構(gòu)整潔之道》書中提到:對于大多數(shù)應(yīng)用,可維護性比可重用性更加重要。
如果你的代碼真的具有很高的復(fù)用性,那可以提升到項目外層目錄,封裝到獨立的hook文件。
尤雨溪的看法
compostion API在提案的時候,就有很多人持有不同意見,有反對有支持,實際上都沒有錯,只是大家碰到的場景不同而導(dǎo)致不同觀點。我通過閱讀compostion API的RFC,找到了作者對一些問題的解答,整理了一些關(guān)鍵問題,內(nèi)容不是完全翻譯,完整內(nèi)容建議查看原文。原文地址https://github.com/vuejs/rfcs/issues/55
問題一:compostion api根本沒有解決任何問題,只是追逐新玩意的東西
尤雨溪: 不同意這個觀點。Vue最開始很小,但是現(xiàn)在被廣泛應(yīng)用到不同級別復(fù)雜度的業(yè)務(wù)領(lǐng)域,有些可以基于option API很輕松處理,但是有些不可以。例如下面的場景:
- 有很多邏輯的大型組件(數(shù)百行)
- 在多個組件可復(fù)用的邏輯
對于問題1,你需要把每個邏輯拆分到不同選項,例如,一段邏輯需要一些響應(yīng)數(shù)據(jù),一個計算屬性,一些監(jiān)聽屬性還有方法。你去了解這段邏輯時,需要不斷上下移動閱讀,雖然你知道一些屬性是什么類型,但是你并不知道他具體的作用。當(dāng)一個組件包含多個邏輯,情況就更糟糕了。如果用新的API,可以將數(shù)據(jù)和邏輯組合在一起,最重要的是,你可以干凈的把這些邏輯提取到一個函數(shù),甚至一個單獨的文件中。
問題二:使用新API導(dǎo)致邏輯分散到不同地方,違背"關(guān)注點分離"
尤雨溪: 這個問題和項目文件組織方式問題類似。我們很多人都同意按文件類型組織(布局放HTML,樣式CSS,邏輯JS)并不是正確的方式,因為強制把相關(guān)代碼分割到三個文件,只是給人一種“關(guān)注點分離”的錯覺。這里的關(guān)鍵是“關(guān)注點”不是由文件類型定義。相反,我們大多數(shù)選擇以功能或者職責(zé)來組織文件,這正是人們喜歡Vue單文件組件的原因。SFC就是按功能組織代碼的方法,但諷刺的是當(dāng)首次引入SFC時,許多人也是拒絕的,認(rèn)為它違反了關(guān)注點分離。
問題三:新的語法讓Vue失去簡單性,導(dǎo)致"意大利面條式代碼"的出現(xiàn),降低項目維護性。
尤雨溪: 正好相反,新的API就是為了提高項目長期維護性的。
如果我們查看任何javascript項目,都會從入口文件開始閱讀,該文件的本質(zhì)是你的應(yīng)用啟動時被隱式調(diào)用的"main"函數(shù)。如果只有一個函數(shù)入口,會導(dǎo)致意大利面條代碼,那所有的js項目都是意大利面條代碼。顯然不是的,因為開發(fā)人員通過代碼模塊化或者較小的函數(shù)來組織代碼。
另外,我同意新的API理論上會降低代碼質(zhì)量的最低門檻。但是我們可以使用以往防止代碼變成意大利面條的手段緩解這種情況。另一方面,新的API可以提升代碼質(zhì)量的最高上限,相比option api,你可以重構(gòu)為質(zhì)量更高的代碼。而且,基于Option api 你還得解決類似mixins的問題。
很多人認(rèn)為"Vue失去簡單性",實際上只是失去組件內(nèi)代碼類型檢查能力(就是你不知道一個變量時data、method、還是computed)。但是用新的API,實現(xiàn)一個類型檢測器也是非常容易實現(xiàn)以前的特性的。也就是說,你不應(yīng)該被option api限制思維,而更多關(guān)注邏輯內(nèi)聚問題。
總結(jié)
上面只是節(jié)選了RFC討論的幾個小問題,如果你對新API還有其他疑問,建議去github閱讀原文,原文討論了非常多問題,我就不一一總結(jié)了。
但是從討論的內(nèi)容和我實戰(zhàn)的經(jīng)驗,用新的API,一定要注意轉(zhuǎn)變代碼組織思維,記住一個詞"邏輯關(guān)注點"。
原文地址:https://zhuanlan.zhihu.com/p/403880140?utm_source=tuicool&utm_medium=referral