摘要:擴展單一職責原則又稱單一功能原則,面向?qū)ο笪鍌€基本原則之一。馬丁表示此原則是基于湯姆狄馬克和的著作中的內(nèi)聚性原則發(fā)展出的。
[解讀]Thinking in React
前言原文:http://facebook.github.io/react/docs/thinking-in-react.html
Thought is the seed of action
這是放置在官方的QUICK START中的一篇博文,文章的目的是教會我們用React的方式去思考如何構(gòu)建一個應(yīng)用。
本文并非為了翻譯,而是注重表達自己學(xué)習過程中的解讀,加深對React組件化開發(fā)方式的認知,如果需要查看原文的翻譯,可以戳這里
原文的翻譯有點坑,個人覺得譯文有些地方并沒有準確地表達原文的意思,甚至有些錯誤
理解React的組件化開發(fā)假如我們要構(gòu)建一個這樣的應(yīng)用
后臺已經(jīng)有JSON API提供這樣的數(shù)據(jù)
[ {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"}, {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"}, {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"}, {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"}, {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"}, {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"} ];
接下來,我們分為5步來構(gòu)建這樣的一個商品搜索的應(yīng)用。
步驟1:將UI拆分成組件樹在此步驟,我們要完成這樣的一個過程:
那么問題來了,如何劃分組件?文章給出了兩個思考這個問題的角度。
1. 單一功能原則
舉例來說,在寫程序的時候,通常為了實現(xiàn)某一單一的功能而創(chuàng)建一個函數(shù)或者一個對象,劃分組件也是類似的一個思路。單一功能原則,指的是在理想狀態(tài)下一個組件應(yīng)該只做一件事情。當一個組件的功能變多了,就應(yīng)該拆分成若干個小的組件。
> 擴展:單一職責原則(SRP:Single responsibility principle)又稱單一功能原則,面向?qū)ο笪鍌€基本原則(SOLID)之一。它規(guī)定一個類應(yīng)該只有一個發(fā)生變化的原因。該原則由羅伯特·C·馬丁(Robert C. Martin)于《敏捷軟件開發(fā):原則、模式和實踐》一書中給出的。馬丁表示此原則是基于湯姆·狄馬克(Tom DeMarco)和Meilir Page-Jones的著作中的內(nèi)聚性原則發(fā)展出的。
筆者認為,運用這一原則可以定位到應(yīng)用的最小功能模塊,從而劃分出最低層的組件。然而,這一原則并不能完全概況組件化開發(fā)的理念,單一職責原則實質(zhì)上提供的是模塊化的思想,指導(dǎo)開發(fā)者編寫低耦合、高內(nèi)聚的代碼。組件化則是一個更為復(fù)雜的概念:組件有層級關(guān)系,父子組件之間還會涉及數(shù)據(jù)傳遞(有時候是雙向的)。如圖所示:
2. 數(shù)據(jù)與UI的對應(yīng)關(guān)系
用戶的界面和數(shù)據(jù)模型在信息構(gòu)造(information architecture)方面具有一致性,即用戶界面可以很好地映射到一個構(gòu)建正確的JSON數(shù)據(jù)模型上。因此在將用戶界面劃分成組件的時候,就是將其劃分成能與數(shù)據(jù)模型一一對應(yīng)的部分。
知道了如何劃分組件,我們就對原型進行劃分
在這個APP中,有5個組件,他們分別是
FilterableProductTable(橙色):包含整個例子的容器
SearcBar(藍色):接收用戶的輸入
ProductTable(綠色):展示并且根據(jù)用戶的輸入過濾商品
ProductCategoryRow(青色):顯示每個類別信息
ProductRow(紅色):展示一行產(chǎn)品信息
實際上對ProductTable的劃分是不夠完美的,因為表格的頭部(即Name、Price一行)并不是它的一部分,而是可以多帶帶劃分出來的組件。由于表格的頭部目前相對的簡單,就簡單地處理了。但是當表格的頭部變得復(fù)雜起來的時候,講道理的話,應(yīng)該將其多帶帶劃分成組件ProductTableHeader。
這樣,我們也可以很容易得到組件樹:
FilterableProductTable
SearchBar
ProductTable
ProductCategoryRow
ProductRow
步驟2:創(chuàng)建靜態(tài)的版本為了節(jié)省篇幅,就不在此處貼出代碼了,如果需要可以參照原文中的代碼或者參照本人自己寫的demo
按照步驟1的分析,我們可以很快地建立應(yīng)用的靜態(tài)版本,每個組件目前只有一個render函數(shù),返回每個組件的html結(jié)構(gòu),同時,建立了組件之間的層級關(guān)系。不過要注意兩點:
在render函數(shù)中使用了JSX,它是JavaScript的一種語法糖,使用的目的是為了編程的便利,可以很清晰看到我們創(chuàng)建的HTML的標簽結(jié)構(gòu),當然還有其他的好處,在后面會提到。
render中創(chuàng)建的是虛擬的DOM節(jié)點,而非真實的DOM節(jié)點,理解這一點對理解React的高效渲染特點很重要。
props vs state
首先,這兩個指的都是數(shù)據(jù)(類似于數(shù)據(jù)驅(qū)動的思想)。關(guān)于這兩個,在這里做一個簡單的分辨。
1.我們在初始化組件的時候,使用的是props。這就是props很典型的使用方法,它是父組件向子組件傳遞數(shù)據(jù)的方式,在React中,數(shù)據(jù)的傳遞是單向的,也正是基于props來實現(xiàn)。
在頂層組件FilterableProductTable會把后臺的JSON數(shù)據(jù)作為props,從頂層組件一直傳遞下去,實現(xiàn)數(shù)據(jù)的單向流動。
2.state是什么?state只存在于React組件的內(nèi)部,React中創(chuàng)建的組件,實際上是一個狀態(tài)機,當組件的state改變的時候,會觸發(fā)組件進行重選渲染(這一過程還會涉及到虛擬DOM的差分算法,最小化DOM操作)。大致的流程(如圖所示):
明確組件的狀態(tài)的改變,是編寫組件的核心部分,在接下來的步驟3就做這樣一件事情。
步驟3:識別出最?。ǖ峭暾模┐鞺I的狀態(tài)集構(gòu)建一個正確的應(yīng)用,首先需要做的就是找出應(yīng)用的最小的狀態(tài)集。
何謂最小?狀態(tài)集中的任意一個 state都不能由其他的state計算得出。用數(shù)學(xué)來描述就是狀態(tài)集中的元素線性無關(guān)。比如說一個TODO List的應(yīng)用,一個state使用數(shù)組保存了條目數(shù)據(jù),那么就不用再使用一個state來保存條目數(shù)了,因為條目數(shù)就是數(shù)組的長度。
回到我們的應(yīng)用中來,在我們的例子中有這么些數(shù)據(jù)(state和props都是數(shù)據(jù))
原始產(chǎn)品信息列表
用戶輸入的搜索數(shù)據(jù)
checkbox的值
搜索過濾之后的產(chǎn)品信息列表
理解了最小之后,我們來確定狀態(tài)集??梢詮膸讉€角度排除掉非state的情況:
數(shù)據(jù)是否是通過props從父組件傳遞過來的?如果是,那么很有可能不是state
數(shù)據(jù)是否會隨時間變化?如果不會,那么也很有可能不是state
是否能通過組件中的props或者其他的state計算出該數(shù)據(jù)?如果是,那就不是state
分析
原始的產(chǎn)品列表信息是通過props進行傳遞,因此不是state
用戶輸入的搜索信息和checkbox都是隨時間變化而且不能通過其他進行計算,應(yīng)該是state
搜索過濾之后的產(chǎn)品信息列表可以通過原始產(chǎn)品信息列表、輸入框信息和checkbox計算得出,因此不是state
到這里,我們得到了應(yīng)用的狀態(tài)集
輸入框的值
checkbox的值
步驟4:確認state存在哪個組件中擁有了狀態(tài)集之后,接下來就要確認哪些組件擁有哪些state。
這里是譯文的一個錯誤的地方,并非確認state的生命周期
我們可以從幾個方面來解決這個問題:
找出那些需要基于該state進行渲染的組件
找到這些組件的共同的祖先組件
要么是共同的祖先組件,要么是另外一個在組件樹中位于更高層級的組件應(yīng)該擁有這個 state
如果找不出擁有這個 state 的組件,可以創(chuàng)建一個新的組件來維護這個state,并將這個組件添加到所有需要基于該state進行渲染的組件的上面。
回到我們的應(yīng)用中來:
ProductTable需要通過state來展示過濾產(chǎn)品信息,SearchBar需要基于state來顯示輸入的文本和checked的狀態(tài)。
它們共同的祖先組件是FilterableProductTable
結(jié)合以上所述,可以很容易得出FilterableProductTable擁有應(yīng)用的兩個state:輸入框的值和checkbox的值
步驟5:添加反向的數(shù)據(jù)流這里可以思考3個問題:
什么叫反向的數(shù)據(jù)流?
為什么要有反向的數(shù)據(jù)流?
怎么實現(xiàn)反向的數(shù)據(jù)流?
首先,在React中,數(shù)據(jù)是從頂層傳遞到底層的。如果是底層的組件通過某種方式更新了上層的組件的state,這樣就叫做反向的數(shù)據(jù)流。
結(jié)合我們的應(yīng)用來講為什么要有反向的數(shù)據(jù)流。在步驟4中,我們得出了組件FilterableProductTable中有兩個state:輸入框的值和checkbox的值,但是這兩個狀態(tài)的改變是由在組件SearchBar中的輸入框的enter事件和checkbox的change事件來觸發(fā)的,同時state的值需要從輸入框的輸入文本和checkbox的值中獲取,這就要求數(shù)據(jù)從SearchBar傳遞到FilterableProductTable中。
“理都懂”之后,來談?wù)剬崿F(xiàn)。我們結(jié)合一下代碼來講解一下(代碼只是大致的實現(xiàn)):
var FilterableProductTable = React.createClass({ handleSearch : function(search) { //searchText為輸入框的值,在此函數(shù)內(nèi)可以改變state this.setState(search) //之后的邏輯省略 } render : function () { return (); } }); 寫在最后); } }); var SearchBar = React.createClass({ handleEnter : function(e) { //...省略前面的判斷邏輯 /*獲取到輸入框和checkbox的值之后,利用props傳遞到父組件, 在這里實現(xiàn)了反向的數(shù)據(jù)流 */ this.props.onSearch({searchText : searchText,isChecked : false}) }, handleChange : function(e) { }, render : function() { return (
到此結(jié)束。在發(fā)布這篇博客的時候,demo并沒有全部完成,估計要過些日子才能完成了。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/79613.html
摘要:前言本文是學(xué)習這一章后的記錄,并且用實現(xiàn)其中的示例。因此得到如下結(jié)構(gòu)而數(shù)據(jù)則從頂層組件往下流動,各層提取各自數(shù)據(jù)進行渲染。而交互的意思是,對的操作會影響應(yīng)用數(shù)據(jù),從而刷新。更新值更新值注意中使用時,需要定義一個返回函數(shù)的高階函數(shù)來實現(xiàn)。 前言 ?本文是學(xué)習Thinking in React這一章后的記錄,并且用Reagent實現(xiàn)其中的示例。 概要 構(gòu)造恰當?shù)臄?shù)據(jù)結(jié)構(gòu) 從靜態(tài)非交互版本...
摘要:,谷歌給的一份性能指南和最佳實踐。目前而言,前端社區(qū)有三大框架和。隨后重點講述了和兩大前端框架,給出了大量的文章教程和相關(guān)資源列表。我認為,使用函數(shù)式編程方式,更加符合后端程序員的思路,而是更符合前端工程師習慣的框架。 showImg(https://segmentfault.com/img/bVbjQAM?w=1142&h=640); 這個是我訂閱 陳皓老師在極客上的專欄《左耳聽風》...
摘要:,谷歌給的一份性能指南和最佳實踐。目前而言,前端社區(qū)有三大框架和。隨后重點講述了和兩大前端框架,給出了大量的文章教程和相關(guān)資源列表。我認為,使用函數(shù)式編程方式,更加符合后端程序員的思路,而是更符合前端工程師習慣的框架。 showImg(https://segmentfault.com/img/bVbjQAM?w=1142&h=640); 這個是我訂閱 陳皓老師在極客上的專欄《左耳聽風》...
摘要:本篇開始介紹自定義組件是如何渲染的。組件將自定義組件命名為,結(jié)構(gòu)如下經(jīng)過編譯后,生成如下代碼構(gòu)建頂層包裝組件跟普通元素渲染一樣,第一步先會執(zhí)行創(chuàng)建為的。調(diào)用順序已在代碼中注釋。先看圖,這部分內(nèi)容將在下回分解 前言 React 是一個十分龐大的庫,由于要同時考慮 ReactDom 和 ReactNative ,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級非常深,閱讀其源碼是一個非...
摘要:在學(xué)習源碼的過程中,給我?guī)椭畲蟮木褪沁@個系列文章,于是決定基于這個系列文章談一下自己的理解。到此為止,首次渲染就完成啦總結(jié)從啟動到元素渲染到頁面,并不像看起來這么簡單,中間經(jīng)歷了復(fù)雜的層級調(diào)用。 前言 React 是一個十分龐大的庫,由于要同時考慮 ReactDom 和 ReactNative ,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級非常深,閱讀其源碼是一個非常艱辛的過...
閱讀 1660·2021-11-22 09:34
閱讀 1537·2021-09-22 14:57
閱讀 3599·2021-09-10 10:50
閱讀 1651·2019-08-30 15:54
閱讀 3826·2019-08-29 17:02
閱讀 3609·2019-08-29 12:54
閱讀 2774·2019-08-27 10:57
閱讀 3455·2019-08-26 12:24