不要再用 Vue 2 的思維寫 Vue 3 了
作者: 蟹老板愛寫代碼
https://juejin.cn/post/6946387745208172558
升級(jí)Vue3后,讓人最腦殼疼的應(yīng)該是新的Compostion API語(yǔ)法,他的難點(diǎn)不是語(yǔ)法,而是他提供了全新的組織代碼的思維方式。
我剛從Vue2轉(zhuǎn)到Vue3時(shí),代碼都嚴(yán)格的遵循Compostion API寫法,但是發(fā)現(xiàn)比Option API寫法維護(hù)性更差。
踩過的坑
1. 按技術(shù)類型劃分代碼
在日常開發(fā)中,前端一般會(huì)收到交互稿或設(shè)計(jì)稿后開始布局,然后編寫邏輯代碼。在Vue2中,通常做法是響應(yīng)數(shù)據(jù)放到data、邏輯方法放到methods,這樣的做法非常方便,也讓我們很容易組織代碼。
當(dāng)使用vue3的Compostion API時(shí),如果還是用Vue2的形式組織代碼,這不但不會(huì)提升代碼質(zhì)量,反而因?yàn)槿狈s束而降低可讀性。
我在github隨便找了一段代碼,你覺得這段代碼比Vue2簡(jiǎn)潔嗎?
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
}
}
}
實(shí)際上我們過于關(guān)注語(yǔ)法層面改變,而忽略官方文檔提到一個(gè)詞叫:邏輯關(guān)注點(diǎn)!!!!!!, 邏輯關(guān)注點(diǎn)是指表達(dá)同一個(gè)業(yè)務(wù)的代碼內(nèi)聚到一起,這也是單一職責(zé)的指導(dǎo)思想,我們內(nèi)聚的不應(yīng)該技術(shù)類型,而是業(yè)務(wù)邏輯,因?yàn)橛|發(fā)代碼變更的往往是業(yè)務(wù)需求,因此把相同變更理由的代碼放在一起,這才不會(huì)導(dǎo)致散彈式修改。
2.過于關(guān)注邏輯復(fù)用
compostion API一個(gè)特點(diǎn)是提升邏輯復(fù)用,這是沒有錯(cuò)的,但是當(dāng)時(shí)我有一個(gè)錯(cuò)誤觀點(diǎn),就是只有復(fù)用的邏輯才應(yīng)該封裝到hook中。
我們還是回到Vue的官方例子,你會(huì)發(fā)現(xiàn)他把原來放在一個(gè)vue文件的邏輯拆分到composables目錄,目錄下分別定義一個(gè)文件,表示不同的邏輯關(guān)注點(diǎn)。

官方文檔地址[1] | 參考代碼倉(cāng)庫(kù)[2]
這個(gè)文件夾的代碼強(qiáng)調(diào)的并不是邏輯復(fù)用,而是邏輯關(guān)注點(diǎn)分離,這也是compostion API最核心要解決的問題,因?yàn)閼?yīng)用生命周期60%時(shí)間都是在維護(hù)的,而維護(hù)性體現(xiàn)在代碼是否符合單一職責(zé)原則,單一職責(zé)就是把相同的業(yè)務(wù)代碼內(nèi)聚到一個(gè)地方。
所以你不要過于糾結(jié)代碼是否需要復(fù)用,應(yīng)用適當(dāng)?shù)娜哂喾炊黾討?yīng)用的維護(hù)性,《架構(gòu)整潔之道》書中提到:對(duì)于大多數(shù)應(yīng)用,可維護(hù)性比可重用性更加重要。
如果你的代碼真的具有很高的復(fù)用性,那可以提升到項(xiàng)目外層目錄,封裝到獨(dú)立的hook文件。
尤雨溪的看法
compostion API在提案的時(shí)候,就有很多人持有不同意見,有反對(duì)有支持,實(shí)際上都沒有錯(cuò),只是大家碰到的場(chǎng)景不同而導(dǎo)致不同觀點(diǎn)。我通過閱讀compostion API的RFC,找到了作者對(duì)一些問題的解答,整理了一些關(guān)鍵問題,內(nèi)容不是完全翻譯,完整內(nèi)容建議查看原文。原文地址[3]
問題一:compostion api根本沒有解決任何問題,只是追逐新玩意的東西
尤雨溪: 不同意這個(gè)觀點(diǎn)。Vue最開始很小,但是現(xiàn)在被廣泛應(yīng)用到不同級(jí)別復(fù)雜度的業(yè)務(wù)領(lǐng)域,有些可以基于option API很輕松處理,但是有些不可以。例如下面的場(chǎng)景:
有很多邏輯的大型組件(數(shù)百行) 在多個(gè)組件可復(fù)用的邏輯
對(duì)于問題1,你需要把每個(gè)邏輯拆分到不同選項(xiàng),例如,一段邏輯需要一些響應(yīng)數(shù)據(jù),一個(gè)計(jì)算屬性,一些監(jiān)聽屬性還有方法。你去了解這段邏輯時(shí),需要不斷上下移動(dòng)閱讀,雖然你知道一些屬性是什么類型,但是你并不知道他具體的作用。當(dāng)一個(gè)組件包含多個(gè)邏輯,情況就更糟糕了。如果用新的API,可以將數(shù)據(jù)和邏輯組合在一起,最重要的是,你可以干凈的把這些邏輯提取到一個(gè)函數(shù),甚至一個(gè)單獨(dú)的文件中。
問題二:使用新API導(dǎo)致邏輯分散到不同地方,違背"關(guān)注點(diǎn)分離"
尤雨溪: 這個(gè)問題和項(xiàng)目文件組織方式問題類似。我們很多人都同意按文件類型組織(布局放HTML,樣式CSS,邏輯JS)并不是正確的方式,因?yàn)閺?qiáng)制把相關(guān)代碼分割到三個(gè)文件,只是給人一種“關(guān)注點(diǎn)分離”的錯(cuò)覺。這里的關(guān)鍵是“關(guān)注點(diǎn)”不是由文件類型定義。相反,我們大多數(shù)選擇以功能或者職責(zé)來組織文件,這正是人們喜歡Vue單文件組件的原因。SFC就是按功能組織代碼的方法,但諷刺的是當(dāng)首次引入SFC時(shí),許多人也是拒絕的,認(rèn)為它違反了關(guān)注點(diǎn)分離。
問題三:新的語(yǔ)法讓Vue失去簡(jiǎn)單性,導(dǎo)致"意大利面條式代碼"的出現(xiàn),降低項(xiàng)目維護(hù)性。
尤雨溪: 正好相反,新的API就是為了提高項(xiàng)目長(zhǎng)期維護(hù)性的。
如果我們查看任何javascript項(xiàng)目,都會(huì)從入口文件開始閱讀,該文件的本質(zhì)是你的應(yīng)用啟動(dòng)時(shí)被隱式調(diào)用的"main"函數(shù)。如果只有一個(gè)函數(shù)入口,會(huì)導(dǎo)致意大利面條代碼,那所有的js項(xiàng)目都是意大利面條代碼。顯然不是的,因?yàn)殚_發(fā)人員通過代碼模塊化或者較小的函數(shù)來組織代碼。
另外,我同意新的API理論上會(huì)降低代碼質(zhì)量的最低門檻。但是我們可以使用以往防止代碼變成意大利面條的手段緩解這種情況。另一方面,新的API可以提升代碼質(zhì)量的最高上限,相比option api,你可以重構(gòu)為質(zhì)量更高的代碼。而且,基于Option api 你還得解決類似mixins的問題。
很多人認(rèn)為"Vue失去簡(jiǎn)單性",實(shí)際上只是失去組件內(nèi)代碼類型檢查能力(就是你不知道一個(gè)變量時(shí)data、method、還是computed)。但是用新的API,實(shí)現(xiàn)一個(gè)類型檢測(cè)器也是非常容易實(shí)現(xiàn)以前的特性的。也就是說,你不應(yīng)該被option api限制思維,而更多關(guān)注邏輯內(nèi)聚問題。
總結(jié)
上面只是節(jié)選了RFC討論的幾個(gè)小問題,如果你對(duì)新API還有其他疑問,建議去github閱讀原文,原文討論了非常多問題,我就不一一總結(jié)了。
但是從討論的內(nèi)容和我實(shí)戰(zhàn)的經(jīng)驗(yàn),用新的API,一定要注意轉(zhuǎn)變代碼組織思維,記住一個(gè)詞"邏輯關(guān)注點(diǎn)"。
-END-
PS:歡迎在留言區(qū)留下你的觀點(diǎn),一起討論提高。如果今天的文章讓你有新的啟發(fā),歡迎轉(zhuǎn)發(fā)分享給更多人。 前端技術(shù)編程交流群已成立 公眾號(hào)運(yùn)營(yíng)至今,離不開小伙伴們的支持。為了給小伙伴們提供一個(gè)互相交流的平臺(tái),特地開通了官方交流群。掃描下方二維碼備注 進(jìn)群 或者關(guān)注公眾號(hào) 前端技術(shù)編程 后獲取進(jìn)群通道。 —————END————— 推薦閱讀: JavaScript 里的奇葩知識(shí) 2021前端面試題 | 25道計(jì)算機(jī)基礎(chǔ) 初學(xué)前端用代碼實(shí)現(xiàn)一個(gè)網(wǎng)頁(yè)老虎機(jī)游戲 利用Jenkins自動(dòng)部署你的Vue項(xiàng)目 一文讓你30分鐘快速掌握Vue3 最近面試BAT,整理一份面試資料《前端面試BAT通關(guān)手冊(cè)》,覆蓋了前端技術(shù)、CSS、JavaScript、框架、 數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。 獲取方式:關(guān)注公眾號(hào)并回復(fù) 前端 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。 明天見(??ω??)??
