此文已由做者黃鍇受權網易雲社區發佈。
javascript
歡迎訪問網易雲社區,瞭解更多網易技術產品運營經驗。html
組件設計,從簡單來看,就是如何提升編碼效率,提升代碼的複用率的方法,從高級來看,這是一門程序設計的藝術java
最近看了redux做者——Dan Abramov寫的《Presentational and Container Components》 感受受益不淺,發現有不少人都在討論組件模式,做爲一個每次寫需求就抓耳撓腮的思考如何組織代碼結構的人來講,如何更好的在工做中使用設計和使用組件,這確實是一個值得討論的問題。react
注:本文圖片部分參考於Michael Chan 作的有關React component patterns的演講: React component patterns, 有興趣的童鞋能夠去看看。git
首先,咱們先從宏觀的角度來聊聊組件。github
如今不少人如今都在談設計模式,設計模式。什麼是設計模式?設計模式主要是指GoF(四人組)《設計模式》一書中提出了23種設計模式,這23種設計模式被普遍應用在軟件工程中,表明着最佳的實踐方案。而在這些模式中,專門有一個設計模式叫:組合模式(Composite pattern),根據wikipedia的解釋:編程
組合模式的目的是將對象組合成樹型結構來表示部分-總體(part-whole)的層次結構。redux
組合模式使得用戶對單個對象和組合對象的使用具備一致性。設計模式
它有如下優勢安全
可擴展性強:因爲組件間是充分解耦的,你能夠輕鬆的更新,替換組件
編碼高效:因爲把功能拆解開,你能夠專一於每一個子模塊功能的實現。
若是你在如今的工做中使用了框架,你會發現,這些框架基本都使用了組合模式這種設計模式。例如Vue和React的Components,它容許你編寫小的組件,而後經過他們的組合構建出你的實際應用。
在學校,總被老師說,要有大局觀,大局觀。使用組合模式,就能夠很好的鍛鍊你的大局觀。 這裏我以爲雲謙前輩 說的很貼切:
要記得,接到需求的第一步永遠不是寫代碼,而是想清楚你要作什麼,以上帝模式作總體設計。
接下來,就讓咱們在咱們的編程世界扮演一個上帝(準確來講是女挖),看看咱們這個充滿組件世界到底發生了什麼。
在框架類的語言中,組件就是咱們操做的基本單位,React對組件的操做提供了不少實用的API,一個組件就是經過使用這些API,產生了強大的生命力,你能夠把它看做一個功能完善的細胞或者個體,咱們全部的APP都是由這一個個細胞(個體)構成的。
而後,你在平常使用中會發現,有些組件,它老是使用其中的一部分API,有些組件常用另外一部分API。說明這些組件開始有了本身的思考,產生了差別化(你能夠把它看做基因突變)。當這些差別化愈來愈多,咱們發現,這些組件由於各自的能力偏好,逐減組成了不一樣的陣營:
對於組件的陣營分類,有不少的說法:
胖和瘦( Fat and Skinny,)組件
狀態和無狀態/純(Stateful and Stateless/pure)組件
聰明和愚笨(Smart and Dumb)組件
容器和展現( Container and Presentational )組件……
他們本質上都差很少,這裏咱們選用Redux做者Dan Abramov對組件的稱法,叫他們容器和展現組件,這裏使用Container和Components
組件分好了陣營,就要開始制定標準,正所謂無規矩不成方圓,一個良好的組織對肯定他們統一的旗號,核心價值觀,才能方便後續找到更多的同類人,發展壯大。
他們稱本身是統治者,這裏匯聚的都是精英份子,它們習慣管理和組織。做爲高高在上的管理者,能讓下屬去作的事情本身必定不會動手。
所以他們制定了一套符合他們價值觀的標準:
表明結構:我只關心
無樣式:我這裏除了一些包裝div,基本沒有其餘標籤,而且從不具備任何樣式
有狀態:我掌握着核心數據,剩下的事情大家去作
一般由其餘組件生成:咱們一般表明更高等的智慧(通常使用更高階的組件生成)
表明人物:各類Page頁面,路由頁面
他們一般由藍白領組成,表明這着廣大的工人階層,什麼髒活累活都是他們作,他們一般沒有太多想法,只是想簡單的作好本身的工做,少背鍋就好。
在這裏,每一個組件關心的事情不多,他們的志向只是作好本質工做,所以他們制定了一套符合他們工做習慣的標準:
表明渲染:關注
有樣式:基本上dom的渲染和樣式這些髒活累活都在這裏幹。
強調獨立(很重要): 咱們彼此分工明確,不依賴於應用程序的其他部分(例如Flux操做或Store)。
不關心數據:咱們不關心數據怎麼產生的,不要在咱們這裏指定數據的加載方式或變動方式。
接受傳回指令:僅經過props接收數據和回調。
弱狀態:咱們基本不須要有本身的狀態(當咱們這樣作時,它是UI狀態而不是數據)。
表明人物:Search,SiderBar,UserList,Pagintation
這兩種陣營基本是徹底獨立的,因爲這種良好的劃分,他們在社會中能很好的相處(藍色是展現組件,灰色是容器組件。
好了,看他們風風火火的把陣營分了,得給他們找點事幹,看這個社會分工的實際運行效果怎麼樣。
這裏順便提一句React的組件定義,一般有兩種方式類定義和無狀態函數定義
無狀態函數定義:
這樣的好處是它自己是獨立的,沒有狀態的,它只會根據傳入的props(能夠考慮成指令)來修改本身的顯示,這樣的組件就具有很好的通用性,並且修改起來也方便,不用擔憂會影響到別的組件。
var User = ({name}) => ( <span>
{name} </span>);複製代碼
類定義:
若是有些內置的狀態須要維護,或者須要使用生命週期,可使用類定義的方式。
class User extends Component {
constructor(props) {
super(props); this.state = {
name: props.name,
editable: false,
};
}
render(){ return ...
}
}複製代碼
容器組件能夠經過類定義,由於可能會使用到生命週期鉤子(使用dva也可能無需生命週期鉤子)。
若是使用了redux類的狀態管理機制,通常就會由connect生成(Relay的
咱們如今要作一個用戶頁面,咱們把這個任務佈置下去,有一個容器陣營拿到了這個頁面製做指標,而後這些精英開始作組織架構工做,他們以爲完成這個工做須要造三個組件:UserSearch,UserList, UserModal。而後每一個組件須要的處理的指令(數據)也寫好了,放在userXXXProps裏,好了,他們的任務完成,開始去找展現容器陣營的人去實現這些功能。
function Users({ users }) { // 從Redux裏獲取數據
const {
loading,
list,
total,
current,
} = users; // 下發任務
const userSearchProps = {}; const userListProps = {}; const userModalProps = {}; // 總體結構設計
return ( <div>
<UserSearch {...userSearchProps} />
<UserList {...userListProps} />
<UserModal {...userModalProps} />
</div>
);
}
// 指定訂閱數據,這裏關聯了 users
function mapStateToProps({ users }) {
return { users };
}
// 創建數據關聯關係
export default connect(mapStateToProps)(Users);複製代碼
通常來講,展現容器推薦使用 無狀態函數 的方式生成
一個良好的展現容器應該是彼此獨立的,這也是一個良好的分工社會應該具有的,你們各司其職,所以這裏一般使用無狀態函數生成一個組件。在這裏,一般是根據props傳入的值去處理相應的事情(老闆要你幹嗎就幹嗎)。
// 從props裏獲取指令(數據)const UserList = ({
total,
current,
loading,
dataSource,
}) => {const columns = [……];// 開始工做,構建組件的渲染return ( <div>
<Table
columns={columns}
dataSource={dataSource}
loading={loading}
/>
</div>);
}複製代碼
這樣看下來,這種社會分工好像運行的挺順暢的。那這就是這個社會的全貌嗎?固然不是,實際的生活中,組件的區分能夠更加精確更加精細。
例若有一些組件設計模式裏把組件模式細分爲:
Proxy component
Presentational component
Layout component
Container component
Higher-order component (HOC's)
Render callback
可是,我我的認爲以上兩種劃分已經足夠應付生活中的絕大部分情形,剩下的,能夠經過二者的組合實現mixed Component。
這樣看下來,這種社會分工好像運行的挺順暢的,實際上,這種分類方式也是 不少開發者經驗的總結。
根據「約定優於配置(convention over configuration)」的思想,提早作必定的規範確定是沒錯的,但不少人將這種分工看作了他們設計組件的教條,這樣就很差了,由於凡事總有例外,也許在某些複雜的業務場景中,Container 和 Components須要混用。你須要靈活的去使用,這也是爲何Dan修改了本身文章:
I amended the article because people were taking the separation as a dogma. 90% of React users don’t ever plan to have something like a living styleguide. There is no need to make life harder for them. Even those that do, don’t need to make
適合本身的纔是最好的。
何苦讓生活更艱難?
最後,再說說比較好的應用開發步驟是什麼?我以爲多是:
完全弄清楚你要作什麼
功能的劃分
根據功能組織目錄結構
設計你的數據模型(modal)
設計你的容器,肯定總體框架結構
開始依次填充展現容器
鏈接組件和數據模型
測試
Presentational and Container Components
React.js Conf 2015 - Making your app fast with high-performance components
Guide to Using the Composite Pattern with JavaScript
更多網易技術、產品、運營經驗分享請點擊。
相關文章:
【推薦】 [翻譯]pytest測試框架(一)