摘要:搜索文本和多選框因為會發生變化,且不能通過計算得出,所以是狀態。最后,過濾過的產品列表,可以通過原始產品列表搜索文本和多選框值計算出來,因此它不是狀態。從傳入的回調函數會調用,從而更新組件。
在使用JavaScript開發大型、快速的網頁應用時,React是我們的首選。在Facebook和Instagram,React很好地減少了我們的工作量。
React最強大部分之一,是讓你在開發應用的同時,按照開發應用的思路去思考。這篇文章,將指導你通過幾個步驟,用React開發一個可搜索數據表
假設我們已經有了一個JSON API和一個設計師設計的模型。看起來像這樣:
我們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"} ];第一步:將UI分解為組件結構
首先,在模型圖上框處每個組件(和子組件),并給組件命名。如果與設計師一起工作,他可能已經心中有數,不妨和他聊聊。他們Photoshop圖層名可能就能成為你的組件名!
但如何劃分父組件子組件呢?就像創建一個函數或對象一樣。其中之一是單一職責原則,理想情況下,一個組件僅做一件事。如果一個組件太大,它應該被分解為更小的子組件。
如果經常把JSON數據模型展現給用戶,你會發現,若模型創建正確,UI(以及組件結構)能很好的反映數據。這是因為UI和數據模型一定程度都是依附于信息架構的,這意味著,將UI分解為組件并不是最重要的,最重要的是,被分解的組件能準確表現你數據模型的一部分。
可以看出,我們的app有五個組件,我們用斜體表示每個組件所代表的數據。
FilterableProducTable(可過濾產品表,橙色):包含整個示例
SearchBar(搜索欄,藍色):接收用戶輸入
ProductTable(產品表,綠色):根據用戶輸入,展示和過濾數據集
ProductCategoryRow(產品分類行,藍綠色):顯示為每個分類的頭部
ProductRow(產品行,紅色):每個產品顯示為一行
觀察ProductTable,你會發現表頭(包含“Name”和“Price”標簽部分)未被劃分為一個組件。表頭是否做為組件屬于個人偏好,至于使用哪種方式,以下可以作為參考。本例中,表頭作為ProductTable的一部分,因為表頭屬于渲染的數據集的一部分,所以表頭在ProductTable的職責范圍內。但如果表頭變得更為復雜(如為添加排序功能),將表頭分離為ProductTableHeader更合理。
現在,我們已經將模型劃分為了組件,接著要安排組件的層次結構。這并不難,模型中一個組件出現在另一個組件的內部,在層次結構呈現為它的一個子級。
FilterableProductTable
SearchBar
ProductTable
ProductCategeoryRow
ProductRow
第二步:創建React靜態版本class ProductCategoryRow extends React.Component { render() { return; } } class ProductRow extends React.Component { render() { var name = this.props.product.stocked ? this.props.product.name : {this.props.product.name} ; return ( {this.props.category} ); } } class ProductTable extends React.Component { render() { var rows = []; var lastCategory = null; this.props.products.forEach(function(product) { if (product.category !== lastCategory) { rows.push( {name} {this.props.product.price} ); } rows.push( ); lastCategory = product.category; }); return (
Name | Price |
---|
{" "} Only show products in stock
現在,你已經有了組件的層次結構,是時候實現這個app了。最簡單的方式,利用數據模型渲染一個無交互的UI版本。創建組件靜態版本需要敲很多鍵盤,無需過多思考,而添加交互效果需要很多思考,不需要敲很多鍵盤,這正是極好的解耦過程。
用數據模型創建app的靜態版本,你在創建組件時會想著復用其它組件,想著用屬性來傳遞數據,而屬性是父級向子級傳遞數據的方式。即便你熟悉狀態的概念,創建靜態版本時也不要用任何狀態。狀態僅用作交互,狀態數據隨時間而變化,因為靜態版本無需任何交互,所以沒必要使用任何狀態。
在層級結構中,既可以自上而下開始創建組件(從FilterableProductTable開始),也可以自下而上開始創建組件(從ProductRow開始)。簡單的例子中,自上而下的方式往往更簡單,對于大型項目來說,自下而上的方式更簡單,更容易測試。
該步完成時,你已經有了一些可復用的組件,這些組件渲染了你的數據模型。靜態版本的組件僅有render()方法。頂層組件(FilterableProductTable)會把數據模型作為一個屬性。如果數據模型發生變化,再次調用ReactDOM.render(),UI會被更新。你可以很容易的看出UI是如何被更新的,哪兒發生了改變。React的單向數據流(也叫單向數據綁定),使得一切變得模塊化,變得快速。
簡述:屬性與狀態屬性和狀態是React中的兩種數據模型,理解兩者的區別非常重要。如果你無法確定兩者的區別,請瀏覽官方文檔
第三步:確定描述UI的最少狀態為了讓UI可以交互,需要能夠觸發數據模型發生改變。React的狀態能讓此變得簡單。
為了能正確的創建app,你要考慮app需要的最少狀態。關鍵在于不重復,使用最少的狀態,計算出所有你需要的數據。例如,你創建一個TODO列表,只需要保留一個TODO項數組,不需要再使用一個變量來保存TODO項數量,當你需要渲染TODO項數目時,使用TODO項數組長度即可。
考慮示例應用中所有的數據,我們有:
原始產品列表
用戶輸入的搜索文本
多選框的值
過濾過的產品列表
簡單地問三個問題,讓我們過一遍,看看哪些是狀態:
是否為從父組件傳入的屬性?如果是,或許不是狀態
是否是隨時間不變的?如果是,或許不是狀態
是否能通過組件中的其他狀態或屬性計算出來?如果是,不是狀態
原始產品列表是從屬性傳入的,因此不是狀態。搜索文本和多選框因為會發生變化,且不能通過計算得出,所以是狀態。最后,過濾過的產品列表,可以通過原始產品列表、搜索文本和多選框值計算出來,因此它不是狀態。
最終,我們的狀態有:
用戶輸入的搜索文本
多選框的值
第四步:確定狀態應該放置的位置class ProductCategoryRow extends React.Component { render() { return (); } } class ProductRow extends React.Component { render() { var name = this.props.product.stocked ? this.props.product.name : {this.props.product.name} ; return ( {this.props.category} ); } } class ProductTable extends React.Component { render() { var rows = []; var lastCategory = null; this.props.products.forEach((product) => { if (product.name.indexOf(this.props.filterText) === -1 || (!product.stocked && this.props.inStockOnly)) { return; } if (product.category !== lastCategory) { rows.push( {name} {this.props.product.price} ); } rows.push( ); lastCategory = product.category; }); return (
Name | Price |
---|
{" "} Only show products in stock
OK,我們已經確定了app的最少狀態。接下來,我們要確定哪個組件是可變的,或者說狀態屬于哪個組件。
記住,React在層級及結構中,數據向下流動。這或許不能馬上清楚狀態究竟屬于哪個組件。這經常也是初學者認識React最有挑戰性的部分。所以,按照以下步驟,弄清這個問題:
對于應用中的每個狀態:
確認每個需要這個狀態進行渲染的組件
找到它們共有的父組件(層級結構中,所有需要這個狀態的組件之上的組件)
讓共有父組件,或者比共有父組件更高層級的組件持有該狀態
如果你找不到合適的組件持有該狀態,創建一個新的組件,簡單持有該狀態。把這個組件插入層級結構共有父組件之上
將這個策略用到我們的應用中:
ProductTable要根據狀態過濾產品列表,SearchBar要顯示搜索文本和多選框狀態
共有父組件是FilterableProductTable
FilterableProductTable持有過濾文本和多選框值很合理
Cool,就這樣決定把狀態放置到FilterableProductTable。首先,在FilterableProductTable的constructor中添加示例屬性this.state = {filterText: "", inStockOnly: false} ,來初始化狀態。然后,將filterText和isStockOnly作為屬性傳入ProductTable和SearchBar。最后,使用這些屬性過濾ProductTable中的行,和設置SearchBar中表單的值
第五步:添加反向數據流class ProductCategoryRow extends React.Component { render() { return (); } } class ProductRow extends React.Component { render() { var name = this.props.product.stocked ? this.props.product.name : {this.props.product.name} ; return ( {this.props.category} ); } } class ProductTable extends React.Component { render() { var rows = []; var lastCategory = null; this.props.products.forEach((product) => { if (product.name.indexOf(this.props.filterText) === -1 || (!product.stocked && this.props.inStockOnly)) { return; } if (product.category !== lastCategory) { rows.push( {name} {this.props.product.price} ); } rows.push( ); lastCategory = product.category; }); return (
Name | Price |
---|
this.inStockOnlyInput = input} onChange={this.handleChange} /> {" "} Only show products in stock
目前為止,我們已經用屬性和狀態,創建了具有在層級結構中至上而下的數據流?,F在,是時候支持反向的數據流動,讓底層表單組件能夠更新FilterableProductTable中的狀態。
React的單向數據流動使得程序更加清晰易懂,但相比雙向數據綁定,確實需要多打些代碼。
如果你嘗試在當前示例中,輸入文本或選擇多選框,會發現React忽略了你的輸入。這是故意的,因為我們要設置input的value屬性要恒等于FilterableProductTable傳入的狀態。
思考下我們期望的狀況。我們希望,表單中無論何時發生改變,用戶的輸入要能夠更新狀態。因為組件應該只更新自己的狀態,所以FilterableProductTable會將回調函數傳遞給SearchBar,SearchBar會在要更新狀態時調用回調函數。我們用onChange事件通知狀態更新。從FilterableProductTable傳入的回調函數會調用setState(),從而更新組件。
雖然聽起來有點復雜,但是也就添加幾行代碼。它非常清晰地表現出了app中的數據流動。
就這樣希望此文能帶給你使用React創建組件和應用的思路。盡管你可能需要打比平時更多的代碼,但記住,代碼看著總是遠比打著的時候多,并且這些代碼都是模塊化、清晰而易讀的。當你開始開發大型組件庫的時候,你將會慶幸React的數據流清晰和模塊化的特性,并且隨著代碼的復用,代碼規模會開始縮小。
原文鏈接thinking-in-react
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81609.html
摘要:它并不是實際在內部的工作方式,而且它只是一個提案,在未來都會有可能發生變化。這意味著,數據的存儲是獨立于組件之外的。因此,有一個訣竅就是你需要思考作為一組需要一個匹配一致的指針去管理的數組染陌譯。 原文地址:https://medium.com/@ryardley/... 譯文:染陌 (Github) 譯文地址:https://github.com/answershuto/Blog 轉...
摘要:注不做翻譯是中最小的構建部件。在里渲染讓我們看一下在下面有在你文件中無處不在的標簽我們會把這元素成為元素因為的所有東西都會放在這個元素里面。通過方法,我們能吧渲染到我們根節點上。更新被渲染的是不可變的。 下面是react官方文檔的個人翻譯,如有翻譯錯誤,請多多指出原文地址:https://facebook.github.io/re...特別感謝Hevaen,同時也向豪大React群所有...
摘要:一般來說,聲明式編程關注于發生了啥,而命令式則同時關注與咋發生的。聲明式編程可以較好地解決這個問題,剛才提到的比較麻煩的元素選擇這個動作可以交托給框架或者庫區處理,這樣就能讓開發者專注于發生了啥,這里推薦一波與。 本文翻譯自FreeCodeCamp的from-zero-to-front-end-hero-part。 繼續譯者的廢話,這篇文章是前端攻略-從路人甲到英雄無敵的下半部分,在...
摘要:擁抱異步編程縱觀發展史也可以說成開發的發展史,你會發現異步徹底改變了這場游戲??梢赃@么說,異步編程已成為開發的根基。這也是你應盡早在上投入大量時間的一處核心知識點,這其中包含和等重要概念。這也是最突出的一項貢獻。 原文地址:Medium - Learning How to Learn JavaScript. 5 recommendations on how you should spend ...
閱讀 1382·2021-10-14 09:43
閱讀 4228·2021-09-27 13:57
閱讀 4560·2021-09-22 15:54
閱讀 2558·2021-09-22 10:54
閱讀 2371·2021-09-22 10:02
閱讀 2114·2021-08-27 13:11
閱讀 873·2019-08-29 18:44
閱讀 1646·2019-08-29 15:20