表单
在 React 中,HTML 表单元素和其它的 DOM 元素有一点不同,因为表单元素天生的保持一些内部状态。例如,这个普通的 HTML 表单接收一个单一的 name:
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
这个表单有默认的 HTML 表单行为,当用户提交表单时,会跳转到新的页面。如果你想在 React 中有这个行为,它也是有效的。但是大多数情况下,让一个 JavaScript 函数来处理表单的提交和访问用户输入的数据是比较方便的。实现这个效果的标准方式是使用称为“受控组件”的技术。
受控组件
在 HTML 中,表单元素如<input>
、<textarea>
和<select>
通常基于用户的输入维护或更新自身的状态。在 React 中,可变的状态通常保存在组件的 state 属性,并且只能使用setState()
来更新。
我们可以通过使 React state 成为“单一数据源”来使两者结合。然后 React 组件渲染一个表单并控制这个表单在随后的用户输入中发生了什么。用这种方法被 React 控制 value 的 input 表单元素被称为“受控组件”。
例如,我们想使之前的例子在提交的时候显示输入的 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上试试。
由于我们的表单设置了value
属性,value 的显示一直会是this.state.value
的值,使 React state 成为单一数据源。由于每次输入都会运行handleChange
来更新 React state,用户的输入会作为 value 的更新显示。
使用一个受控组件,每一个 state 的变化都会有一个与之相关联的处理函数。这使得修改或验证用户的输入变得更简单明确。例如,我们想让用户的输入强制变成大写,我们可以把handleChange
写成这样:
handleChange(event) {
this.setState({value: event.target.value.toUpperCase()});
}
textarea 标签
在 HTML 中,<textarea>
元素通过它的子元素定义它的文本:
<textarea>
Hello there, this is some text in a text area
</textarea>
在 React 中<textarea>
使用一个value
属性代替。这种方式,textarea
表单的编写和编写单行 input 表单非常类似:
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>
注意,由于selected
属性,Coconut 选项是被默认选择的。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上试试。
总的来说,这使得<input type="text">
、<textarea>
和<select>
工作方式非常相似——它们都接收一个value
属性,你可以使用它来实现一个受控组件。
替代受控组件
有时使用受控组件是乏味的,因为你需要通过一个组件为所有的数据变化的方式和管道处理所有的输入 state 编写事件处理器。当你转换一个已存在的代码库到 React,或使用非 React 库整合一个 React 应用时,这一点尤为恼人。在这种情况下,你可能想查看非受控组件,一个实现 input 表单的另类技术。
下一步
提升 State