前端組件化開發中的陷阱

在前端開發領域,隨著react、vue(前端組件化UI框架)等框架的流行,組件化成為前端領域最熱門的概念之一。但實際上組件化開發很早就已經出現,並在軟體開發(主要是GUI軟體)領域得到廣泛應用。

任何一種開發模式都有其適用範圍,基本不存在一種不考慮使用場景放之四海而皆準的模式,在適當的場景下使用適當的開發模式往往會達到事半功倍的效果,組件化開發模式同樣如此,有些場景下組件化並不是最優的解。

視圖不是標準的樹狀結構

組件化是把整個展示層抽象成一個自上而下的樹狀結構,每一個節點是一個組件,像搭積木一樣搭出整個視圖。但如果有這樣視圖裡面的元素並不是一層一層,一個節點一個節點有序的排列,而是在一定的空間內按照一定的規律運動,就像原子內部的電子一樣是一種混沌的狀態,如果繼續用組件化開發,會導致開發和維護成本都很高。這樣說可能有點抽象,下面舉個例子:

假設我們要實現一個彈幕功能,需要在視頻播放區域展示彈幕,規則如下

1、每行字幕不能重複,並且一行一行順序從上往下排

2、字幕按賬號或者其他的規則分優先順序,不同優先順序的規則不同(比如字型大小顏色等)

3、彈幕可以開關

4、有控制面板可以控制字幕,包括全局的控制和局部的(可能是每種優先順序的彈幕)

5、彈幕內容點擊可以回復

...

實際場景中可能還有其他規則,可以想見,這樣一種場景很難抽象成一個dom樹出來,而且數據流向是雙向的,同一個彈幕有多個控制點,如果用組件化的方式,可能是下面這樣的

很明顯這樣的結構無法滿足我們的需求,因為優先順序B的彈幕並不是集中在一個區域,而是分散的,而且會擋住下面的彈幕,導致我們無法操作。

但有人會說,為何不把每條彈幕當做一個節點,這樣從布局上來說沒問題,但維護成本太高,而且如果這樣的話實際上就不是組件化了,因為每個節點都是平鋪的沒有層級結構,這樣的話只是打著組件名義的「組件化」。

我們可以換種思路,首先,忘掉組件,回歸問題,我們會發現整個需求是有規律可尋的,我們把每條彈幕想成一個點

1、每個點有自己的屬性,包括速度,字型大小顏色等等

2、同一類的點可以同時控制(比如同時關閉)

3、每個點自己的狀態要上報,比如屏幕之外的話這個點的數據要銷毀

...

到這裡,基本我們有個大概的思路了,這裡沒有樹狀的dom結構,只有控制和被控制,是不是和某種設計模式很像。。。

是的,`發布-訂閱模式`,整個的結構大概是這樣

這裡的虛擬dom也並不是需要實現一個完整的虛擬dom,這是一個描述彈幕節點的對象而已,這裡用虛擬dom的概念只是為了說明問題,最後只需要把這個對象render成真實的html即可

是不是清楚多了,:-)

慎用局部狀態

在組件式開發中,因為每個組件都是獨立存在的,組件之間都是低耦合的,這樣才能更好的保證組件的可移植性,所以每個組件維護自己的狀態是一件很正常的事情。而且這種開發模式在之前(準確的說是react興起之前)是很常見的一種方式,每個組件是自成一體的,只對外暴露api,接收屬性參數。

濫用局部狀態帶來的副作用

首先我們看看單獨維護狀態有什麼問題

如果每個組件維護自己的狀態,就意味著整個應用裡面的元素狀態被分割成多個獨立的小塊,雖然有些狀態確實是組件內部的狀態,不會影響到組件之外的元素,但實際上並不能保證完全一個狀態完全是對外無關的,有可能不同的場景下會有不一樣的結果。

狀態分隔帶來兩個問題:同步性和狀態回朔。

1、同步性

維護多個模塊的狀態的同步性是一個很複雜的問題,尤其是應用變的很複雜的時候,這個是比較明顯的。除此之外,這樣的設計也更容易出現問題,假設有個tab組件,用戶點擊tab按鈕之後下面的panel內容會更新,每個panel都存在一個表格,表格裡面的數據是需要提交到後端的。由於組件之外的某個bug,導致要提交的form數據沒有同步,但是因為組件自己維護狀態,用戶點擊之後就會切換panel,這個時候顯示界面其實已經和真實情況不符了,這是一個比較極端的例子,但這樣的問題在前端開發裡面也不少見。

2、可回朔性

回朔就是說某個組件可以回到之前的某個狀態。

不可維護也就意味這不可回朔,假設只有一個組件,每一次操作都會保留「上一次狀態」,這樣很容易回到「之前的狀態」,但是應用變得複雜之後,一種狀態的「之前的狀態」會變得很混亂,基本很難去描述。

單一原子狀態

react開發提供了一種更加直觀和易維護的範式:單一原子狀態。在組件化開發中(不限於react),如果我們可以更明確的貫徹這種理念,上面提到的問題基本就不會存在。

什麼是單一原子狀態?

單一原子狀態就是說一個應用只保存一份「最終的數據」來描述整個應用,具體到我們提到的組件化開發,如果每個組件的狀態我們也遵循同樣的原則,每個組件就是一個「無狀態組件」,他的狀態完全由數據驅動,上面提到的「同步性」和「可回朔性」也就迎刃而解了。

實際上,在redux就是這樣一種範式的具體體現,這裡不再具體詳述。

說這麼多並不是說組件化開發是一個不好的開發模式,只是說在某些場景下完全套用組件化並不是最優解,對任何一種開發模式我們都應該結合具體場景做出評估。組件化依然是目前和今後前端開發中最常用的模式選擇,但我們需要避免一些「陷阱」。


推薦閱讀:

為什麼CPU越來越多地採用硅脂而不是焊錫散熱?
如果我想要深入的學習計算機目標跟蹤方向的內容,應該從哪個方面開始入手,比如說看什麼書?
那麼我想知道那些計算機語言的創始人是如何創造這門語言的?
如何看待某託管在 GitHub 的前端開源項目關閉 Issue 欄目的行為?
為什麼機械硬碟隨機讀取性能和連續讀寫性能差那麼多?

TAG:计算机技术 | 前端开发框架和库 |