# 表单
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),是一个实现输入表单的替代技术。