在React中,HTML 表单元素与其他DOM元素略有不同,因为表单元素天生自带内部状态。例如,简单的HTML表单接受一个名字:
<form>
<label>
Name:
<input type="text" name="name" />
</label>
<input type="submit" value="Submit" />
</form>
当用户提交表单时,这个表单有浏览新页面的默认HTML表单行为。在React中你想要这个行为,那么它会有效工作。但是大多数时候,方便的是有一个JavaScript函数,这个函数处理表单的提交和获取用户输入的数据。实现这个的标准方法是一个叫“controlled components”的技术。
Controlled Components
在HTML中,表单元素如<input>,<textarea>和<select>经典维持它们自己的状态和基于用户输入更新状态。在React中,易变的状态由组件的状态属性保持,仅能用setState()更新。
通过React状态是个真实的资源来合并这俩,那么React组件也控制随后用户输入在表单中的反映。以这种方式被React控制的input表单元素被称为"controlled component".
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);
}
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属性绑定在我们的表单元素上,展示的值总是this.state.value,使React状态称为真实的资源。因为handleChange运行在每个键上,显示值将随用户打字更新。
一个controlled component,每个状态变化都有一个关联的处理函数。这使修改或者验证用户输入变得简单。例如,我们想要强制名字以大写字母书写,我们可以这样写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在构造函数中被初始化,因此text area显示它其中的初始文本。
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属性,所以被初始化为选择。代替使用selected属性,React在select标签中使用value属性。用controlled component 更方便,因为你只需要在一个地方更新它。例如:
class FlavorForm extends React.Component{
constructor(props){
super(props);
this.state={value:'coconut'};
this.handleChange=this.handleChange.bind(this);
this.handleSubmit=this.handleChange.bind(this);
}
handleChange(event){
this.setState({value:event.target.value});
}
handleSubmit(event){
alert('Your favorite flavor is: '+this.state.value);
}
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上试试吧。
Overall,this makes it so that <input type="text">,<textarea>,and <select>all work very similarly -they all accept a value attribute that you can use to implement a controlled component.
总之,达到了预期日期,因此<input type="text">,<textarea>,和<select>非常相似的工作,他们都接受一个value属性,用这个属性可以实现controlled component.
Handling Multiple Inputs
处理多个Input
When you need to handle multiple controlled input elements,you can add a name attribute to each element and let the handler function choose what to do based on the value of event.target.name.
当你需要处理多个控制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>
);
}
}
在CodePen试试吧。
注意和给input名字一样,我们怎样使用ES6计算属性名语法更新状态键。
this.setState({[name]:value
});
等价ES5的代码如下:
var partialState={};
partialState[name]=value;
this.setState(partialState);
setState()手动将一部分状态合并至当前状态中,我们只需要调用它改变的部分。
Controlled Components的优化
使用controlled components有时是冗长的,因为你需要为组件中数据能改变和管道化所有输入状态的每个方面写处理器。当你将现存的代码库转换为React或者用非React库整合成React,这会变得特别烦人。遇到这种局面,你可能想要检验uncontrolled components,实现input表单的一个优化技术。
https://facebook.github.io/react/docs/uncontrolled-components.html