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