導語:前端開發者必然會遇到單個元件有多種UI的情況,UI種類越多,重複工作量越大,本文基於React提供一種解決思路。
1. 元件示例
拿一個商品元件舉例,總共十幾種UI形式,這裡列舉三種
商品標題 最大行數 |
是否展示庫存標籤 |
是否展示商品推薦詞 |
右下角功能 |
|
|
2 |
✅ |
❌ |
加購 |
|
2 |
❌ |
❌ |
加購 |
|
1 |
✅ |
✅ |
增加數量 |
2. 常規解法
遇到這種問題,常規的解法是封裝獨立小元件,例如
- 商品圖片元件
- 商品標題元件
- 商品標籤元件
- 商品xxx元件...
完整元件的程式碼結構大概是
<div className="goods-item">
<GoodsImage image="xxx" />
<GoodsTitle title="xxx" />
<GoodsTag tagList={[]} />
{type === 'cart' && <GoodsCart />}
{type === 'num' && <GoodsNum />}
</div>
但這個方案存在一個弊端,當元件樣式比較少的時候一片祥和,隨著元件樣式不斷增多,問題會逐漸暴露,主要體現在:
- 通用邏輯每個頁面都要重新呼叫,比如埋點上報、點選跳轉商詳,導致重複程式碼增多。
- 如果迭代一個小元件,那麼所有使用的地方都要手動更新入參,導致維護成本大。
- 骨架屏的粒度控制比較麻煩,每個元件都要給小元件們傳入loading引數
- 程式碼複雜度越高,後期維護引起現網bug的機率越大。
3. 尋求出路
剖析它們的異同點,可以發現每個元件的資料結構和業務邏輯幾乎是一模一樣的,只有UI表現不一樣,而它們耦合得比較深,根據高內聚低耦合原則,可以將它們的相同點(資料結構和業務邏輯)內聚起來,而差異點解耦到各頁面中。
但如何做呢?React提供一種renderProps的語法,可以在一個根元件中將業務邏輯處理好,再吐出小元件供商品元件例項使用,根元件不關心UI,而元件例項只關心UI。
更生動形象的描述:
- 樂高工廠接收塑膠原材料 -> 沖模加工成不同形狀 -> 生產出一堆標準化零件 -> 使用者自由組裝成不同的造型
- 根元件接收商品資料 -> 處理所有業務邏輯 -> 生產出一堆標準化小元件 -> 開發者自由組裝UI
這樣不僅擁有常規方案的所有特性,而且能完美解決上述那些問題。
4. 程式碼重構
建立商品根元件
首先在根元件裡處理了曝光埋點、點選跳轉等通用邏輯;
其次封裝了很多小元件,每個useCallback都是一個獨立的可開箱即用的小元件,每個小元件都支援傳入style和className來定製樣式,然後將小元件吐出去給外部使用。
小元件示例
拿最簡單的商品標題元件舉例,它支援兩個額外引數
- maxLine:文字最大行數,超出則用省略號溢位隱藏
- isShowTag:是否展示文字前面的標籤
通用的商品標題渲染由元件內部處理,其他透過小元件的擴充套件引數支援。
根元件渲染了什麼
一般元件的children是實體dom元素,但我們利用React的renderProps特性,children定義成一個函式,外部在使用根元件時,透過傳入一個函式引用來實現自由度極高的自定義渲染。
使用根元件
可以很明顯的看到,外部在使用根元件進行渲染自定義商品元件時,沒有任何業務邏輯程式碼,它的職責非常單一且明確:只需關心UI表現。整塊程式碼看起來非常清爽。
4. 最終效果
這是其中一種UI改造前後程式碼量的對比:
感受完視覺衝擊,再來看看彙總資料:
- 改造定製化元件14個,程式碼量減少了900+行,佔元件總程式碼量的60%。
- 後期維護成本減少80%
- 改造後半年內相關現網bug由2降為0
可以看出改造效果非常顯著。