原文连接:reactjs.org/docs/forms.…html
React中表单元素与其余元素的有些不一样,由于表单元素自己就是带有状态的。如今让咱们来看看下面这段代码:react
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
复制代码
这个表单带有HTML自带的默认行为:当用户点击submit
时,浏览器进入一个新的页面。在React中,表单是默认带有这一行为的。但在大多数状况下,咱们须要一个JavaScript函数来处理用户输入的数据和提交事件。实现这种方式的标准方法是使用受控组件。数组
在HTML中,表单元素如<input>
,<textarea>
,<select>
自身就带有状态并根据用户输入来更新自身的UI。可是在React中,可变的状态一般保存在组件的state
属性中,而且只能经过setState()
来更新state。浏览器
咱们能够将二者结合起来,使React的state成为“惟一数据源”。渲染表单的组件还控制着用户输入数据时表单的操做,以这种方式被React控制输入值的表单元素被称为受控组件。bash
若是咱们想在上一个例子的代码中在用户提交时将用户输入的姓名打印出来,咱们能够将表单写为受控组件:服务器
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('提交的名字: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
名字:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="提交" />
</form>
);
}
}
复制代码
因为咱们在表单元素上设置了value
属性,如今展现的输入值就一直都是this.state.value
的值,这就让React的state
成为了惟一数据源。由于伴随着每次用户敲击键盘输入数据,handleChange
函数也被调用去更新state,因此展现的数据就像用户写入的同样更新。函数
在受控组件中,状态的改动都关联着一个处理函数,这使得修改或者校验用户输入变得简单。好比咱们想要用户输入的姓名都是大写英文字母,咱们能够这样改写handleChange
:学习
handleChange(event) {
this.setState({value: event.target.value.toUpperCase()});
}
复制代码
在HTML中,<textarea>
标签的文本由它的子元素决定。ui
<textarea>
Hello there, this is some text in a text area
</textarea>
复制代码
在React中, <textarea>
则用一个value属性代替子元素。这样,使用<textarea>
的表单和使用单行输入的表单就很是类似。this
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>
Essay:
<textarea value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
复制代码
this.state.value
在构造函数中被初始化,因此text area最开始就是有值的。
在HTML中,<select>
标签建立了一个下拉列表,下面的代码表示了一个香料的下拉列表:
<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中,咱们使用在<select>
标签上的value
属性代替在<option>
上的selected
属性。这在受控组件里是很是方便的由于咱们只须要在一个地方更新数据就能够了。
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 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>
);
}
}
复制代码
总的来讲,这种方式使得<input type="text">
, <textarea>
和 <select>
的工做方式十分类似:都接收一个value属性。你可使用它们来实现受控组件。
提示 你能够在
<select>
标签的value属性上传递一个数组,这样就能够选择多行选项。<select multiple={true} value={['B', 'C']}>
在HTML中,<input type="file">
标签让用户从他们的设备上选择一个或多个文件上传到服务器或由JavaScript 文件API操做。
<input type="file" />
复制代码
由于它的状态是只读的,因此在React中它是一个非受控组件。它将会和其余非受控组件一块儿在后面的章节里讨论。
当你须要处理多个受控的input元素时,你能够给每一个input元素添加一个name
属性,并让处理函数根据event.target.name
的值来选择如何操做。
例如:
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
<form>
<label>
Is going:
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
</label>
<br />
<label>
Number of guests:
<input
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
</form>
);
}
}
复制代码
这里咱们使用ES6计算属性名称
来根据name属性更新对应key的state。
this.setState({
[name]: value
});
复制代码
这与下面ES5代码是等价的:
var partialState = {};
partialState[name] = value;
this.setState(partialState);
复制代码
另外,因为setState()
会自动合并state到当前的state,因此咱们只须要调用它来更改部分state便可。
在受控组件上指定value的值能够阻止用户更改输入。可是若是你指定了value的值但输入依然能够被更改,那么有多是你将value
值设置为undefined
或null
。
下面的代码展现了这种状况。最初input是被锁定的,但过了一会就变成可更改的了。
ReactDOM.render(<input value="hi" />, mountNode);
setTimeout(function() {
ReactDOM.render(<input value={null} />, mountNode);
}, 1000);
复制代码
使用受控组件可能会让你决定单调。由于你须要为每个数据输入编写处理函数,将全部的输入状态绑定到组件中。当你要将原先的项目转化成Reac应用或将React应用改写成非React应用时就会让人很是烦躁了。在这种状况下,你可使用一种替代技术来实现表单,非受控组件。
若是你正在寻找一个可以提供校验,跟踪访问字段和处理提交事件功能的解决方案,那么Formik就是你最好的选择。Formik时创建在受控组件和状态管理的原则上的,因此请不要忘记学习它哟。