在咱們的理念中,React 最初的目的是使用 JavaScript 建立大型的,快速響應的網絡應用。它在咱們的 Facebook 和 Instagram 中已經實踐的很是好了。css
React的衆多優勢之一是它讓你在編寫代碼的時候同時也在思考你的應用。在這篇文檔中,咱們會帶你使用 React 一塊兒建立一個可搜索的產品數據表格,並向你展現咱們的思考過程。html
想象咱們已經有一個 JSON 接口和一個設計師給咱們的原型圖。原型圖像下面這樣:react
咱們的 JSON 接口返回相似下面的數據:數組
[
{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"}
];
第一件你要作的事情是用方框劃分出每個組件(和子組件)並給他們命名。若是你和設計師一塊兒工做,他們可能已經完成了這些,因此去和他們聊聊吧!他們的 Photoshop 圖層名稱也許就是你的 React 組件名稱!網絡
但你如何知道哪一部分應該成爲一個組件?想一想在編寫代碼時你在什麼狀況下須要新建一個函數或對象,思考方式是同樣的。例如 單一功能原則,在理想情況下,一個組件應該只作一件事情。若是這個組件功能不斷豐富,它應該被分紅更小的組件。架構
既然你常常向用戶展現 JSON 數據模型,你會發現,若是你的模型構建正確,你的 UI (以及你的組件結構)會被很好的映射。這是由於 UI 和數據模型每每遵循着相同的信息架構,這意味着將 UI 劃分紅組件的工做每每是很容易的。只要把它劃分紅能準確表示你數據模型的一部分的組件就能夠。app
在這裏你會看到,咱們的簡單應用中有5個組件。咱們把每一個組件展現的數據用斜體表示。模塊化
FilterableProductTable
(橙色): 包含了整個例子SearchBar
(藍色): 接受全部的用戶輸入ProductTable
(綠色): 根據用戶輸入過濾並展現數據集合ProductCategoryRow
(綠松石色): 展現每一個分類的標題ProductRow
(紅色): 用行來展現每一個產品若是你查看 ProductTable
,你會發現表頭(包含 Name
和 Price
標籤)並無做爲一個組件。這是一個偏好問題,選擇哪一種方式目前還存在爭議。在這個例子中,咱們把它做爲 ProductTable
的一部分,由於它是渲染數據集合的一部分,而渲染數據集合是 ProductTable
的職責。然而,若是頭部變得更加複雜(也就是,若是咱們添加了排序功能),它就有足夠的理由成爲一個單獨的 ProductTableHeader
組件。函數
如今咱們已經肯定了原型圖中的組件,讓咱們把它們整理成層級結構。這很容易。原型圖中的子組件在層級結構中應該做爲子節點。測試
FilterableProductTable
SearchBar
ProductTable
ProductCategoryRow
ProductRow
See the Pen Thinking In React: Step 2 on CodePen.
如今有了組件層級,是時候去實現你的應用了。最簡單的方式是先建立一個靜態版本:傳入數據模型,渲染 UI 但沒有任何交互。最好把這些過程解耦,由於建立一個靜態版本更多須要的是碼代碼,不太須要邏輯思考,而添加交互則更多須要的是邏輯思考,不是碼代碼。咱們會看看爲何是這樣的。
要構建一個用於呈現數據模型的靜態版本的應用程序,你須要建立可以複用其餘組件的組件,並經過 props 來傳遞數據。props 是一種從父級向子級傳遞數據的方法。若是你熟悉 state 的概念, 在建立靜態版本的時候不要使用 state。State 只在交互的時候使用,即隨時間變化的數據。因爲這是靜態版本的應用,你不須要使用它。
你能夠自頂向下或者自底向上構建應用。也就是,你能夠從層級最高的組件開始構建(即 FilterableProductTable
開始)或層級最低的組件開始構建(ProductRow
)。在較爲簡單的例子中,一般自頂向下更容易,而在較大的項目中,自底向上會更容易而且在你構建的時候有利於編寫測試。
在這步的最後,你會擁有一個用於呈現數據模型的可重用組件庫。這些組件只會有 render()
方法,由於這只是你的應用的靜態版本。層級最高的組件(FilterableProductTable
)會把數據模型做爲 prop 傳入。若是你改變你的基礎數據模型而且再次調用 ReactDOM.render()
, UI 會更新。很容易看到你的 UI 是如何更新的,哪裏進行了更新。由於沒有什麼複雜的事情發生。React 的單向數據流(也叫做單向綁定)保證了一切是模塊化而且是快速的。
若是你在這步須要幫助,請參閱 React 文檔
在 React 中有兩種數據模型:props 和 state。理解二者的差異是很重要的;若是你還不肯定差異是什麼,請查看React 官方文檔
爲了使你的 UI 交互,你須要可以觸發對底層數據模型的更改。React 使用 state,讓這變的更容易。
爲了正確構建你的應用,首先你須要考慮你的應用所須要的最小可變狀態集。要點是 DRY:不要重複(Don’t Repeat Yourself)。找出應用程序的絕對最小表示並計算你所須要的其餘任何請求。例如,若是你正在建立一個 TODO 列表,只要保存一個包含 TODO 事項的數組;不要爲計數保留一個單獨的狀態變量。相反,當你想要渲染 TODO 計數時,只須要使用 TODO 數組的長度就能夠了。
想一想咱們的實例應用中全部數據。咱們有:
讓咱們來看看每一條,找出哪個是 state。每一個數據只要考慮三個問題:
原產品列表被做爲 props 傳入,因此它不是 state。搜索文本和複選框彷佛是 state,由於它們隨時間改變而且不能由其餘任何值計算出來。最後,產品的篩選列表不是 state,由於它能夠經過將原始產品列表與搜索文本和複選框的值組合計算出來。
最後,咱們的 state 有:
See the Pen Thinking In React: Step 4 by Kevin Lacker (@lacker) on CodePen.
好的,如今咱們肯定了應用 state 的最小集合。接下來,咱們須要肯定哪一個組件會改變,或擁有這個 state。
記住:React 中的數據流是單向的,並在組件層次結構中向下傳遞。一開始咱們可能不是很清楚哪一個組件應該擁有哪一個 state。在新手理解上這一般是最富有挑戰性的部分,因此按照下面的步驟來辨別:
對你應用的每個 state:
讓咱們用這個策略分析咱們的應用:
ProductTable
須要根據 state 過濾產品列表,SearchBar
須要展現搜索文本和複選框狀態。FilterableProductTable
。FilterableProductTable
。很酷,因此咱們決定把 state 放在 FilterableProductTable
。首先,爲 FilterableProductTable
的 constructor
添加一個實例屬性 this.state = {filterText: '', inStockOnly: false}
來表示咱們應用的初始狀態。接下來,把 filterText
和 inStockOnly
做爲 prop 傳入 ProductTable
和 SearchBar
。最後在 ProductTable
中使用這些 props 來篩選每行產品信息,在 SearchBar
中設置表單域的值。
如今你可以看到你的應用是如何運做的了:設置 filterText
的值爲 ball
並刷新你的應用。你會看到數據表格正確的更新了。
See the Pen Thinking In React: Step 5 on CodePen.
到目前爲止,咱們已經建立了一個能夠正確渲染的應用程序,它的數據在層級中經過函數的 props 和 state 向下流動。如今是時候支持其餘方式的數據流了:層級結構中最底層的表單組件須要去更新在 FilterableProductTable
中的 state。
React 的數據流很明顯,讓你能夠很輕鬆的瞭解你的程序是如何運行的,但相較於傳統的雙向綁定,它的代碼量會稍微多一點。
在當前版本的示例中,若是你試圖鍵入或選中複選框,你會發現 React 會忽略你的輸入。這是故意的,由於咱們把 input
的 value
屬性設置爲一直等於從 FilterableProductTable
傳入的 state
.
讓咱們想一想咱們想要作什麼。咱們想確保每當用戶更改表單時,咱們更新狀態來反應用戶輸入。由於組件應該只更新本身的狀態, FilterableProductTable
會將一個回調函數傳遞給 SearchBar
,每當應該更新狀態時,它就會觸發。咱們可使用輸入上的 onChange
事件來調用它。FilterableProductTable
傳入的回調函數會調用 setState()
,這時應用程序會被更新。
雖然這聽起來很複雜,但它只是幾行代碼的問題。並且,你能夠清楚地看出你的應用中數據是如何流動的。
但願這可讓你瞭解如何使用 React 構建組件和應用程序。雖然這可能會比之前編寫更多的代碼,但請記住,代碼是用來讀的,這比寫更重要,而且很是容易閱讀這個模塊化的,思路清晰的代碼。當你開始構建大型組件庫的時候,你會開始欣賞 React 的思路清晰化和模塊性,而且隨着代碼的複用,你的代碼量會開始減小。:)