無論是vue還是react,核心思想離不開元件化,而元件化中,脫離了傳統的操作DOM對UI狀態的改變,更進一步通過對資料的操作來改變UI狀態,避免了直接操作DOM的繁瑣和易出現的bug。
而元件化中的關鍵兩點就是元件的props和state,說直白一點就元件的屬性和狀態。這兩點是如何貫穿在元件化開發流程中和怎樣顛覆傳統的操作DOM對UI狀態改變,在此稍作個人理解輸出。
下面換一種不同以往列舉程式碼的方式和一張拙劣的簡筆畫來輸出一下個人見解。
蓋房子
要想理解這些概念是什麼以及如何使用它們,我們先來寫一個小示例。就蓋個房子如何?
元件
元件化開發
第一步是將 UI 分解成多個元件。例如,我們可以這樣來拆分房子:
現在來編碼!
House:
<div>
<Roof /> // 房頂
<Wall /> // 牆
<Window /> // 窗
<Door /> // 門
</div>複製程式碼
等一下,怎麼看起來這麼像 HTML ?沒錯!React 的部分程式碼看上去就是非常像 HTML ,其實就是這樣設計的,這是為了讓 Web 設計師理解和編寫 React 程式碼更容易一些。
因此,在上面的程式碼中,我們使用 <div> 作為容器,這基本和 HTML 中是一樣的。而像 Roof 和 Wall 這樣的標籤是我們即將定義的自定義標籤/元件。
溫馨提示: 上面的程式碼並非實際的 React 程式碼,甚至連 JavaScript 都算不上。暫時,我們只使用這種寬鬆的語法來介紹概念。一旦你理解這些概念後,我們再來學習 JavaScript 的細節並將上述概念轉換成真實程式碼。
為了讓這個例子更容易理解一些,我再簡化一下: 從現在開始,我們來寫一個超級簡單的 Web 應用,連圖片都不用,只顯示文字。
例如,Roof 其實就是一個裡面有文字的 div :
Roof:
<div>roof</div>複製程式碼
其他元件也是如此,都是隻有文字的 div 而已。首先,我們來看下房子的完整的 React 風格的程式碼:
House:
<div>
<Roof />
<Wall />
<Window />
<Door />
</div>
Roof:
<div>roof</div>
Wall:
<div>wall</div>
Window:
<div>window</div>
Door:
<div>door</div>複製程式碼
這沒什麼不好理解的,是吧?House 是由 Roof、Wall、Window 和 Door 組成的,這些都是純文字構成的元件。
最後,React 生成的 HTML 如下所示:
<div>
<div>roof</div>
<div>wall</div>
<div>windows</div>
<div>door</div>
</div>複製程式碼
使用 Props 來配置屋頂的顏色
想象一下,我們將規格說明書發給一個工廠,這個工廠負責代工所有的零部件。在規格說明書中,我們可以告訴工廠每個部件的固有屬性,比如屋頂的顏色、門的形狀,等等。在按照我們的要求將屋頂和門生產出來後,它們的屬性不會產生任何變化,屋頂還是藍色的,門依舊是矩形的。這些屬性壓根不會改變。
在 React 裡,我們將這些屬性稱之為 Prop ,即 property 的縮寫。關於 Prop ,你需要記住兩點: 首先,我們來決定 Prop 的值,並在元件構建之前將其作為元件設計的一部分。其次,Prop 的值永遠不會改變。
那 prop 在程式碼中是怎樣的呢?在 House 元件中,如果我們想要藍色屋頂的話,只需在 Roof 元件上新增 “color” 屬性。這就好比是在發給工廠的規格說明書中指定顏色。
這有點類似於給 HTML 標籤新增屬性:
House:
<div>
<Roof color="blue"/>
...
</div>複製程式碼
那Roof裡面又是怎麼樣使用 prop 的呢?程式碼如下所示:
Roof:
<div>{props.color} roof</div>複製程式碼
就這樣?沒錯!但是有幾點需要注意:
定義元件的 HTML 風格程式碼是一個模板,而不是單純的 HTML 標籤。這意味著我們可以在其中放置佔位符來改變 HTML 輸出的內容,而不必重複編寫不同的 HTML (還記得 Domo 的帽子嗎?這就是佔位符的概念!)。在這個示例中,<Roof color="blue" /> 生成的 HTML 是 <div>blue roof<div>,而 <Roof color="red" /> 生成的是 <div>red roof</div>,以此類推。
模板中使用的花括號告訴 React 我們要在此處使用佔位符來替代純文字。
props 可以看作是 Roof 元件所有屬性值的集合。假設元件是這樣使用的: <Roof color="blue" material="wood" /> ,那麼在 Roof 元件的定義中就可以使用 props.color 和 props.material 。
使用 State 來開門
為元件新增 State
元件還可以擁有 state 。那麼什麼是 state ?state 是一種可以在元件建立後更改的資料。
舉個例子,門既可以開,又可以關。我們可以說門的狀態就是 state ,因為它的值是可以在門建立後更改的。在這點上,state 與 prop 是不同的,prop 是不會改變的,比如門的形狀。
狀態值的改變通常是由外部事件所引起的。在 Web 應用中,這些所謂的外部事件通常包括:使用者輸入了資料,或者從服務端獲取了資料,又或者是定時器的觸發。
下面,我們來為門新增 state :
Door:
State:
status // "open" 或 "closed"
<div>Door is {state.status}</div>複製程式碼
與 props 類似,state 也是元件內部所有狀態值的集合。因此,我們可以在元件定義的模板中使用 state.[something] 。
接下來,我們來新增一些處理使用者輸入的“虛擬碼”來讓門具有互動性。
Door:
State:
status // "open" 或 "closed"
<div>Door is {state.status}</div>
// 處理使用者輸入
當開門時
將 state.status 修改成 "open"
當關門時
將 state.status 修改成 "closed"複製程式碼
這裡的關鍵點是元件的 state 是隨時間而變化的。模板的輸出,也就是生成的 HTML 會根據 state 的變化而自動改變。
順便說句,不要忘了上面的只是“虛擬碼”,而不是 React 程式碼。不要嘗試將其複製黏貼到你的專案中!否則你的電腦炸了我不負責……
State 是私有的
元件的 state 是私有的。門無論是開還是關,這都僅僅是門的邏輯。與房子或其他元件沒有任何關係。事實上,我們完全可以將門從房子中移出去,它仍然可以自己開啟或關閉。
因此,門的狀態只有在 Door 元件內部是可見的。在 Door 元件內,我們可以讀取或改寫它的 state 。
House:
<div>
<Door />
...
<!-- 下面這句是錯的 -->
<div>The door is {Door.state.status}</div>
</div>
Window:
...
<!-- 下面這句是錯的! -->
將 Door.state.status 修改成 'open'
Door:
...
<!-- 兄dei,這還是錯的! -->
if House.state.正在出售
房產經紀人就可以開門複製程式碼
總結
這就是 prop 和 state 。prop 是元件的配置項,它的值是在元件建立之前就已經決定好了,比如門的形狀和屋頂的顏色就可以定義為 prop。prop 的值永遠不會改變。而 state 是元件的私有資料,當元件建立後才可以使用它。比如門的開關狀態可以包括在 state 裡面。state 會隨著一些外部事件的發生而變化。這些所謂的外部事件通常包括:使用者輸入了資料,或者從服務端獲取了資料,又或者是定時器的觸發。