# 表單
HTML 表單元素跟 React 中的其它 DOM 元素運作有所不同,因為表單元素本身會保留一些內部的狀態。例如,這個純 HTML 表單接受一個單獨的 name:
~~~
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
~~~
這個表單在用戶提交的時候具有默認的導航到一個新頁面的 HTML 表單行為。如果你希望 React 中保持這個行為,也可以工作。但是多數情況下,用一個處理表單提交并訪問用戶輸入到表單中的數據的 JavaScript 函數也非常邊界。標準的方式是使用一個叫做“控制組件”的技術。
## 控制組件
在 HTML 中,表單元素如 `<input>`、`<textare>` 和 `<select>` 一般基于用戶的輸入維護并更新它們自己的狀態。在 React 中,
可變狀態一般保存在組件的 state 屬性中,并且只能通過 [setState()](https://facebook.github.io/react/docs/react-component.html#setstate) 更新。
我們可以通過使 React 的 state 成為“單一源”來結合這兩個形式。然后渲染表單的 React 組件也可以控制在用戶輸入之后的行為。被 React 以這種形式控制值的輸入表單元素,稱為一個“控制組件”。
例如,如果我們希望使前一個例子在被提交的時候打印 name,我們可以編寫它為一個控制組件:
~~~
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
~~~
在 CodePen 中[打開查看](https://codepen.io/gaearon/pen/VmmPgp?editors=0010)。
由于 value 屬性設置在我們的表單元素上,顯示的值總是 this.state.value,使 React state 是實際的源。由于 handleChange 在每個擊鍵運行以更新 React 的狀態,顯示的值將更新為用戶的輸入。
通過一個控制組件,每個狀態變化都有一個相關的處理函數。這使它可以簡單的修改或者驗證用戶輸入。例如,如果我們希望確保 name 使用全部大寫字母,我們可以編寫 handleChange 為:
~~~
handleChange(event) {
this.setState({value: event.target.value.toUpperCase()});
}
~~~
## textare 標簽
在 HTML 中,`<textarea> `元素通過它的子節點定義了它的文本:
~~~
<textarea>
Hello there, this is some text in a text area
</textarea>
~~~
在 React 中,`<textarea>` 使用一個 value 屬性替代。這個方式,使用了 `<textarea>` 的表單可以被編寫為和使用一個單行輸入框的表單非常相似:
~~~
class EssayForm extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 'Please write an essay about your favorite DOM element.'
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('An essay was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<textarea value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
~~~
注意,this.state.value 在構造函數中初始化,所以文本域開始的時候帶有一些文本。
## select 標簽
在 HTML 中,`<select>` 創建了一個下拉列表。例如,這段 HTML 創建一個一個口味列表:
~~~
<select>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option selected value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
~~~
注意,Coconut 選項是初始化被選中的,因為它的 selected 屬性。React 中,并不使用這個 selected 屬性,而是在根 select 標簽中使用了一個 value 屬性。這在一個控制組件中是更方便的,因為你只需要在一處更新它即可。例如:
~~~
class FlavorForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: 'coconut'};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('Your favorite flavor is: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Pick your favorite La Croix flavor:
<select value={this.state.value} onChange={this.handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
~~~
在 CodePen 中[打開查看](https://codepen.io/gaearon/pen/JbbEzX?editors=0010)。
總的來說,這使 `<input type="text">`, `<textarea>` 和 `<select>` 都以類似的方式工作 —— 它們都接受一個 value 屬性可以用來實現一個控制組件。
## 替代控制組件
可能有時候使用控制組件是單調的,因為你需要編寫一個事件處理程序對于每個可修改的數據,并在一個 React 組件中傳遞所有的輸入狀態。這在當你轉換一個現存的代碼庫到 React 可能比較繁瑣,或者和一個非 React 庫集成 React 應用。在這些情況下,你可能希望使用[未控制組件](https://facebook.github.io/react/docs/uncontrolled-components.html),是一個實現輸入表單的替代技術。