HTML的form标签在react和其他标签有一些不同,因为form标签内部有一些状态性的东西,比如下面的HTML代码,form标签会有一个被定义为name的东西:
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
上面的这个表单有一些默认的行为,当点击提交以后会跳到另一个页面中,他在react中也是这样表现的。但是在绝大多是情况下,要是让我们自己定义的函数去处理提交事件,获得用户输入的数据的话,对于我们的系统功能实现而言是一种方便的实践。在React中,上面所提及的方式有一个标准的实现技术,被称作受控制的组件。
受控制的组件
在HTML中,form标签中的元素例如input,textarea,select等是由自己来控制自己状态,并且依据用户的输入来更新状态。在React中,像用户输入这种易改变的值是在组件自己控制的,并且仅仅通过setState函数更新。现在我们将上面两种特性结合起来,这种结合起来的方式被称为单向数据流。这时候React的组件将会控制用户的输入。用这种方式创建的组件被称为受控制的组件。
例如,如果你想用这种组件来实现上面的例子,你可以这样写:
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>
);
}
}
一旦value属性绑定在我们的表单元素上,它的值就会一直和this.state. value保持一致,一旦用户的输入值发生改变,就会立即调用handleChange函数修改this.state.value的值,这样在视图上也就改变了。
有了这种机制,每一个易于改变的state都会和一个句柄函数联系起来,这样,在这个句柄函数中可以讲用户的输入值以任意方式进行改变。例如,我们想将所有输入值变成大写,可以这样写:
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的表单元素可以这样写:
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在构造器中被初始化了,因此textarea在一开始是具有一些值的。
select标签
在HTML中,select标签创建了一个下拉列表,比如,下面的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中,表示被选中的选项不是使用selected属性,而是使用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>
);
}
}
总之,无论是input,textarea,还是select都以value值作为其属性,所以你可以用这个值来将一个组件设置称为受控制的组件。
控制多个控件元素
当你需要控制多个诸如input的控件元素时,你可以给它们添加name属性,这样就可以让控制器根据不同的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的“可计算属性名”的语法:
this.setState({
[name]: value
});
等同于ES5的语法:
var partialState = {};
partialState[name] = value;
this.setState(partialState);