前言
這里寫一下如何封裝可復用組件。首先技術棧 react hooks + prop-types + jsx封裝純函數組件。類組件和typeScript在這不做討論,大家別白跑一趟。
接下來會說一下封裝可復用組件的思路,比如一個新手應該怎么去封裝,都需要注意哪些東西。
然后說一些復雜組件需要的功能,比如閉合標簽內部dom怎么處理,其實就是插槽功能,比如數據監聽,內部做一些業務邏輯。
想看原碼的點這里,這是我GitHub上完整的 react hooks 項目, 點這里,看源碼
目錄
1、思路 及 封裝的誤區
2、 props 的類型檢測、默認值
3、組件調用及數據互通
4、實現類似於vue插槽一樣的功能 (children屬性)
5、useState、useEffect等hooks講解
6、總結
一、思路
無論是js還是C++等等,都要求 模塊內高內聚、模塊間低耦合。簡單點說就是你改了一個模塊,另一個模塊稍作修改就行,不至於改動很大。根據這個編程思想,一個可復用組件的對外交互,就是決定他耦合度的關鍵。把組件比作香腸機,輸入豬肉,輸出香腸。輸入就是props,輸出就是界面效果 以及 給外部反饋的回調函數。關於輸入props,我們對他有要求,就是類型檢查和默認值。比如輸入的得是豬肉不能是石頭,默認做小香腸,而不是大香腸。回調函數也有要求,你得盡可能滿足可以預知的邏輯,簡單說就是你以后用這個組件的時候,需要某個數據,這個組件得支持,得有對應的回調能讓你拿到你想要的的東西。
注意,這里說幾個誤區,也是很多人經常犯錯的地方。
1、項目中可復用組件我認為有2種,並不是所有組件都按照一套標准去規范
第一種 全局可復用組件,這類組件類似於antd那種ui庫,是提供給開發項目所有人使用的,頻率高。這一類必須嚴格規范,不能亂搞。必須有props的類型檢查,有需要的props得加默認值;組件只能接收props作為數據來源,通過回調函數反饋,嚴禁其他任何形式的輸入輸出改(其實回調函數也是props,只不過是函數類型的,為了功能上做區別,后續我都會這樣稱呼);必須對組件功能,props,內部的方法等添加注釋。
第二種 是一些局部功能組件,這一類可能只在部分特定情況下會使用,不需要像第一種那種嚴格要求,比較靈活多變,盡可能以簡單通俗易懂去編寫他,比如接下來要描述的幾種禁忌,這類組件並沒有這些要求,只要代碼精簡、便於維護、易讀。你想怎么寫都行。
2、全局組件
避免使用redux一類的狀態管理,能用props實現就別懶
避免使用ref獲取組件數據,能用回調的都寫上回調,ref可讀性很差
保持純凈,自己開發的組件可以相互引用,但是盡可能避免對第三方、包括UI框架的使用。當然這也不是絕對,二次封裝組件很常見,只是有條件的盡量自己開發。
二、 props 的類型檢測、默認值
我們使用prop-types做props類型檢查,得安裝一下
npm i prop-types
看下面的代碼,首先引入 prop-types ,然后創建我們的函數組件,這里有幾點需要注意的,首先,先定義組件,然后在組件原型上綁定類型檢查;其次因為是函數組件,所有用prop-types做類型檢查的props,都必須在函數組件的形參中顯式的聲明,否則不好使。看代碼也能理解畢竟綁定在原型上,初始化的時候不聲明,就沒辦法綁定校驗了。所以,我建議一種寫法,所有props都做檢查,都在形參中聲明,能賦默認值的,都寫上默認值,然后在形參的后面把注釋都寫明白了,這樣代碼一目了然,換個人也可以很容易接手你的代碼。這里啰嗦一嘴,函數組件,本質就是個函數,所以默認值這些都是js函數形參賦默認值的寫法。
額外啰嗦兩句prop-types的用法,后面這個是他的用法說明: https://zh-hans.reactjs.org/docs/typechecking-with-proptypes.html
鏈接包括所有的類型、一個props聲明多種類型,對象內部屬性的類型校驗,甚至是定義一個類型檢查函數等用法。
三、組件調用及數據互通
處理好了props,我們處理回調,如圖所示,是我寫的一個簡單的回調。這里一般不寫默認值,但是要做非空判斷,因為不是所有的屬性,使用者都需要。每個全局組件都需要有份文檔,不但描述邏輯功能,還有所有屬性的的描述,像函數這類,需要有示例的,形參含義說明白。
四、實現類似於vue插槽一樣的功能 (children屬性)
封裝組件經常會遇到需要 插槽 的情況,簡單說就是你封裝了一個閉合組件,內部的dom你想對他做一些處理,比如樣式上的。這里說一下應該怎么做。看圖,注意,如果有一個根標簽,children就是個對象,如果多個並列標簽的話,children就是數組,用法不一樣,這里根據需求來,我這里用的是對象,也就是頂層只有一個標簽,注意需要定義children的類型,是標簽,還是一個數組的標簽。圖中代碼類型定義是一個react標簽,所以如果別人寫了並列的div,就會報警告這樣自然可以很好的約束使用者。
五、useState、useEffect等hooks講解
最后寫一點函數組件的使用心得。首先父組件變化 或者 函數組件內部變量變化,都會導致函數組件重新執行,如果你在return前面寫個console,會發現執行了很多次,復雜的界面甚至能執行幾十次,這點很操蛋,不過最終diff的時候react會做優化,合並很多變化,當然很多時候執行太多次,還是代碼有問題的,需要你盡可能的優化下代碼,提升性能。其次,函數組件只有hooks,沒有生命周期,這和類組件差異很大,代碼邏輯也改變很大,很多人剛一接觸hooks和函數組件會感覺很懵逼,不知道該怎么寫代碼。關於這點,我不打算在這里講太多,畢竟這是介紹封裝組件的文章。react的文檔屬於心智模型,非常nice,大家應該都能看得明白,接下來我會寫幾個看文檔不容易了解,實際擼代碼又很重要的東西。
1、函數會不斷執行,如果在函數內部聲明變量或者常量會不斷被初始化,所以要么用useState聲明要么直接放到函數外,比如標記1、3 、4。否則,聲明的變量就會是個定值。
2、useState聲明的變量,默認值只會賦值一次,他只會觸發一次,比如標記 2。
3、函數組件沒生命周期,所有功能都集合到useEffect身上了,它 用於監聽變量變化,可以監聽useState的也可以監聽我們那個標記1這種函數外的。他第二個參數傳空數組,就只會在組件初始化的時候執行一次,可以在這初始化數據,發http請求,或者時間綁定等。他的觸發機制實在dom渲染結束之后。比如標記 5,如果加return,卸載的時候也會執行return的邏輯,這其實就是他實現生命周期功能的用法之一。
4、useMemo 通過這個hooks可以優化組件的渲染次數,它根據指定變量變化控制函數是否執行
u
六、總結
關於react hooks封裝可復用組件,暫時就想到了這么多,文章開頭我貼了GitHub的項目地址,因為要說的東西比較多,沒法一個例子就把所有東西清晰、條理的說明白,期間我截圖了好幾個組件的代碼,大家看源碼的話,直接看components文件夾。
vue3的setup參考了react hooks,從用法上說,vue的改變還能讓人接受些,畢竟他只是將之前的屬性換到了setup的原型上。react這波真的是大變樣,類組件和函數組件真的就完全是2套代碼了。
這里說一下我自己的感悟,這兩個框架先是變得雍容華貴,功能很多,現在又返璞歸真,追求靈活,貼近js。對我最大的體會就是以后的碼代碼變難了。升級之后vue和react上手難度都提升了很多,提高了對js基礎的理解。有經驗的程序員寫出的代碼,精簡干練,部分地方,新手可能會看不懂。新手寫出來的代碼,有可能亂成一鍋粥,其他人都看不懂。所以希望大家多寫注釋,好好擼代碼,把這個編程的風氣提高上來。
博主真的是遇到過很多垃圾代碼,深受其苦,大多是大家都不想優化代碼,這糊一塊,那加一段,代碼越來越亂,最后走向重構的結局。裱糊匠太難了