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