前端組件級別的抽象方向

基于2大主流前端框架下,前端的主要的工作其實就是在編寫各種組件。似乎所有人都在說前端開發(fā)的天花板很低,除了一些特別的方向,很少有人在前端功能的開發(fā)上遇到過什么難題。這也導致沒有人關注和討論前端組件的抽象,大家都忙于做功能的開發(fā)。甚至有些前端開發(fā)在完全不做抽象的情況下僅用少數(shù)幾個組件就完成了對整個SPA的開發(fā)。

為什么需要組件級別的模塊抽象?
即使在掘金這樣偏前端的專業(yè)社區(qū),也有很多人認為不需要做模塊抽象。以下是我的上一篇文章《如何把前端項目寫成一座屎山?[1]》下的一個熱門評論:

具體就不做反駁了,因為我根本不知道他在說什么!

模塊化抽象的本質仍舊也逃離不了“高內(nèi)聚、低耦合”這2個永恒的主題。更具體的,主要是為了性能和可維護性。但性能問題往往被直接忽略,因為現(xiàn)代瀏覽器的性能和框架的優(yōu)化極大抹平了這部分差異。所以拋開一些情況下的性能優(yōu)化,我們抽象的意義在于提高了代碼的可維護性,帶來了復用、邏輯內(nèi)聚、穩(wěn)定的開發(fā)效率、較小的心智負擔和bugfree,所以這絕對是一件具有長期收益的事情。

抽象方向
代碼行數(shù)
相信大部分前端開發(fā)都體會過接手別人代碼,打開一個組件模塊,代碼1000+行那種撲面而來的壓迫感。雖然我也看到過代碼行數(shù)控制在小幾百行,抽象依舊稀爛的代碼。但暫時沒見過組件超長但抽象仍舊非常好的代碼。代碼行數(shù)甚至稱不上作為衡量抽象好壞的標準,但絕對是最接近本質的一個表象。就我個人代碼風格而言,極少有封裝超過150行的組件模塊(代碼風格可參考本人開源項目KerryCodes/leggo: 一款拖拽式前端表單生成低代碼工具~ \(github.com\)[2])。

視圖頁面結構
這是最樸素的一個組件抽象方向,社區(qū)里討論的也最多,按下不表。

單一功能
很多開發(fā)總是困惑什么時候應該開始抽象組件,是因為這個組件太大了代碼行數(shù)太多了,所以需要去做拆分嗎?是因為視圖結構上相距甚遠所以拆分嗎?不是的,你應該要考慮的是功能。根據(jù)“單一職能”原則,我們可以基于功能去安排將哪些邏輯抽象成一個獨立的組件模塊。多思考功能級別的拆分,然后把每一個最小原子化功能實現(xiàn)的代碼抽象成一個獨立的組件。

復用公共部分
我們難免遇到一些功能相似的組件,導致在多個組件中重寫了一部分相同或相似的邏輯。不要這樣做,盡量把交叉部分的功能做抽象,達到復用的效果。這里的抽象可以是公共組件也可以是一個公共函數(shù)。如果復用和維護性無法權衡怎么辦?維護性優(yōu)先!不要為了復用一點邏輯搞一堆入?yún)⒒蛱幚泶罅康倪吔鐥l件,導致代碼冗雜難懂,這是不可取的。






自動初始化
這是一個非常常見的功能場景。假設你有一個新建彈窗,里面有一些表單在彈窗開閉的過程中需要恢復初始化值。最常規(guī)的開發(fā)就是通過手動去恢復初始值。但隨著功能的迭代表單值的增刪變化,我們不得不同時也不斷去維護一大塊邏輯用于初始化,這大大增加了開發(fā)的心智負擔,導致維護性性變差。所以,我們的抽象在于使得狀態(tài)初始化過程不需要手動去干預,而交給組件的加載和卸載過程自動去完成。

自定義hooks
相比于Class組件,函數(shù)組件提供了hooks,于是我們有了一個非常強大的帶狀態(tài)的抽象復用手段。明顯的,我們可以將一些公共的業(yè)務邏輯抽象成hooks作為復用手段(當然也更應該首先考慮抽象成一個組件)。另外對于一些非公共的業(yè)務邏輯,只被某個特定組件使用,但是卻比較復雜,比較偏過程,個人也會封裝成hooks使用。這樣做的好處就在于組件內(nèi)部會比較干凈,開發(fā)維護的心智負擔下降。

但我們也并非可以濫用自定義hooks,因為hooks也有一些明顯的缺點。比如副作用,隱式的狀態(tài),邏輯黑盒化等等,這些都增加了心智負擔。(歡迎各位大佬討論這部分內(nèi)容?。?br>
狀態(tài)和重渲染
“狀態(tài)”可以說是前端組件開發(fā)中最重要的一個概念,所有的重渲染都是來自于狀態(tài)的改變。很多bug也是來自于狀態(tài)與視圖不一致的問題。狀態(tài)維護的好壞標準在于狀態(tài)的改變是否引起的是最小原子化的視圖重渲染。如果一個狀態(tài)的改變總是引起與該狀態(tài)毫無關系的其它組件重渲染,那么基本可以確定這一塊代碼的抽象做的很差。這里可以特別提一下“純組件”的優(yōu)化,出現(xiàn)這種優(yōu)化技巧的本質就在于狀態(tài)改變所導致的不必要高成本重渲染。

有一種非常典型的抽象方式就是props.children,也可以歸為這個方向。這個寫法相信很多前端都了解,在面試過程中也是一個高頻八股問題。但這種方式不應該被濫用,因為這會導致代碼視圖結構的清晰度下降。我總結了適用這種抽象的幾個前提:頁面視圖結構導致父子組件無法分離;父子組件關聯(lián)度很低;父組件的狀態(tài)活躍,而子組件不活躍。本質上在于父組件的狀態(tài)變化不引發(fā)子組件的不必要重渲染。

非受控組件
這個概念來自React官方文檔介紹表單組件的部分,我們可以借用一下。如果你的組件總是需要接受來自父組件的傳參,可能就是抽象不好的體現(xiàn)。越多的傳參代表更多的耦合度。

軟件設計有一個非常重要的原則叫“迪米特原則”,這個原則啟發(fā)我們一個模塊應當盡可能少的與其他模塊發(fā)生相互作用。盡量使你的組件保持干凈獨立,狀態(tài)在內(nèi)部完成消化而不是受父組件控制。除了耦合度降低帶來的bugfree,一個明顯的收益是干凈的非受控組件在復用時幾乎是沒有心智負擔的。所以需要非常謹慎的使用狀態(tài)提升這種手段,如非必要可以盡量避免。

申明:以上觀點來自個人經(jīng)驗總結和思考,歡迎理性討論和補充。另外所有方式都需要先考慮具體場景,不要無腦使用!

關于本文

作者:阿佛加德奔

https://juejin.cn/post/7156575298501214221

歡迎關注微信公眾號 :前端Q