我們已經學習如何使用 React?[呈現數據](http://reactjs.cn/react/docs/displaying-data.html)。現在讓我們來學習如何創建交互式界面。
## 簡單例子
~~~
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false};
},
handleClick: function(event) {
this.setState({liked: !this.state.liked});
},
render: function() {
var text = this.state.liked ? 'like' : 'haven\'t liked';
return (
<p onClick={this.handleClick}>
You {text} this. Click to toggle.
</p>
);
}
});
React.render(
<LikeButton />,
document.getElementById('example')
);
~~~
## 事件處理與合成事件(Synthetic Events)
React 里只需把事件處理器(event handler)以駱峰命名(camelCased)形式當作組件的 props 傳入即可,就像使用普通 HTML 那樣。React 內部創建一套合成事件系統來使所有事件在 IE8 和以上瀏覽器表現一致。也就是說,React 知道如何冒泡和捕獲事件,而且你的事件處理器接收到的 events 參數與?[W3C 規范](http://www.w3.org/TR/DOM-Level-3-Events/)?一致,無論你使用哪種瀏覽器。
如果需要在手機或平板等觸摸設備上使用 React,需要調用`React.initializeTouchEvents(true);`?啟用觸摸事件處理。
## 幕后原理:自動綁定和事件代理
在幕后,React 做了一些操作來讓代碼高效運行且易于理解。
**Autobinding:**?在 JavaScript 里創建回調的時候,為了保證?`this`?的正確性,一般都需要顯式地綁定方法到它的實例上。有了 React,所有方法被自動綁定到了它的組件實例上。React 還緩存這些綁定方法,所以 CPU 和內存都是非常高效。而且還能減少打字!
**事件代理 :**?React 實際并沒有把事件處理器綁定到節點本身。當 React 啟動的時候,它在最外層使用唯一一個事件監聽器處理所有事件。當組件被加載和卸載時,只是在內部映射里添加或刪除事件處理器。當事件觸發,React 根據映射來決定如何分發。當映射里處理器時,會當作空操作處理。參考?[David Walsh 很棒的文章](http://davidwalsh.name/event-delegate)?了解這樣做高效的原因。
## 組件其實是狀態機(State Machines)
React 把用戶界面當作簡單狀態機。把用戶界面想像成擁有不同狀態然后渲染這些狀態,可以輕松讓用戶界面和數據保持一致。
React 里,只需更新組件的 state,然后根據新的 state 重新渲染用戶界面(不要操作 DOM)。React 來決定如何最高效地更新 DOM。
## State 工作原理
常用的通知 React 數據變化的方法是調用?`setState(data, callback)`。這個方法會合并(merge)?`data`?到?`this.state`,并重新渲染組件。渲染完成后,調用可選的?`callback`回調。大部分情況下不需要提供?`callback`,因為 React 會負責把界面更新到最新狀態。
## 哪些組件應該有 State?
大部分組件的工作應該是從?`props`?里取數據并渲染出來。但是,有時需要對用戶輸入、服務器請求或者時間變化等作出響應,這時才需要使用 State。
** 嘗試把盡可能多的組件無狀態化。** 這樣做能隔離 state,把它放到最合理的地方,也能減少冗余,同時易于解釋程序運作過程。
常用的模式是創建多個只負責渲染數據的無狀態(stateless)組件,在它們的上層創建一個有狀態(stateful)組件并把它的狀態通過?`props`?傳給子級。這個有狀態的組件封裝了所有用戶的交互邏輯,而這些無狀態組件則負責聲明式地渲染數據。
## 哪些?_應該_?作為 State?
**State 應該包括那些可能被組件的事件處理器改變并觸發用戶界面更新的數據。**?真實的應用中這種數據一般都很小且能被 JSON 序列化。當創建一個狀態化的組件時,想象一下表示它的狀態最少需要哪些數據,并只把這些數據存入?`this.state`。在?`render()`?里再根據 state 來計算你需要的其它數據。你會發現以這種方式思考和開發程序最終往往是正確的,因為如果在 state 里添加冗余數據或計算所得數據,需要你經常手動保持數據同步,不能讓 React 來幫你處理。
## 哪些?_不應該_?作為 State?
`this.state`?應該僅包括能表示用戶界面狀態所需的最少數據。因此,它不應該包括:
* **計算所得數據:**?不要擔心根據 state 來預先計算數據 —— 把所有的計算都放到`render()`?里更容易保證用戶界面和數據的一致性。例如,在 state 里有一個數組(listItems),我們要把數組長度渲染成字符串, 直接在?`render()`?里使用`this.state.listItems.length + ' list items'`?比把它放到 state 里好的多。
* **React 組件:**?在?`render()`?里使用當前 props 和 state 來創建它。
* **基于 props 的重復數據:**?盡可能使用 props 來作為惟一數據來源。把 props 保存到 state 的一個有效的場景是需要知道它以前值的時候,因為未來的 props 可能會變化。