Forms
表单组件,比如:<input>
,<textarea>
和<option>
和基本的组件不同,因为表单组件是需要用户进行交互的。这些组件提供了接口,用来更容易的管理表单来响应用户的交互。
有两种形式的表单组件
1. Controlled Components
2. Uncontrolled Components
Controlled Components
一个受控表单组件提供一个value
属性,一个受控表单组件不会维持其内部自己的状态,组件只根据props进行渲染。
render() {
return (
<input
type="text"
value="Hello!"
/>
)
}
如果你试图去运行这里例子,会发现输入框里的内容不会随着输入而改变。因为你声明了这个组件的value值,为了更新value作为用户输入的响应,需要添加onChange事件来保存新的值,然后传递这个值给value属性。
class Form 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) {
console.log("Text field value is : " + this.state.value);
}
render() {
return (
<div>
<input type="text" placeholder="Hello!"
value={this.state.value} onChange={this.handleChange}/>
<button onClick={this.handleSubmit}>
Submit
</button>
</div>
)
}
}
ReactDOM.render(
<Form />,
document.getElementById("root")
);
在这个例子中,我们接受用户提供的值,来更新value 的值,这种方法使得继承接口或者进行表单验证变得很方便
handleChange(event) {
this.setState({
value: event.target.value.substr(0, 14)
});
}
Checkboxes和RadioButton存在的潜在问题
在使用React来监听checkbox或者radio的事件的时候,React监听一个click的浏览器事件来声明一个onChange事件,在大部分情况下这样是没有什么问题的,除非当你调用了preventDefault()
在change的事件处理函数里面,preventDefault会停止浏览器在视觉上更新输入,即使checked的值已经改变了,这个问题可以通过不调用preventDefault或者将切换checked的值放在setTimeout中执行来解决。
非受控组件
不提供value属性的表单组件称为非受控组件。下面的例子渲染了一个<input>
来控制一个空的值,任何用户输入的值会立刻影响到渲染的元素。
一个非受控组件管理他自己的状态。
render() {
return <input type="text" />
}
如果你希望监听这个组件的值的更新,你需要使用onChange
事件来监听,就像受控组件一样,但是不能给组件传递任何值。
class Form 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("Text field value is : " + this.state.value);
}
render() {
return (
<div>
<input
type="text"
placeholder="Hello!"
onChange={this.handleChange} />
<button onClick={this.handleSubmit}>
Submit
</button>
</div>
);
}
}
ReactDOM.render(
<Form />,
document.getElementById("root")
)
当这个例子输入value的时候,我们可以通过handleSubmit()
来读取,非受控表单组件不能够请求,你需要完整的onChange
事件处理来取代读取value
。
默认值
使用一个非空的value
来初始化一个非受控组件,你可以使用一个defaultValue
属性
render() {
return <input type="text" defaultValue="Hello" />
}
同样地,<input type="checkbox">
和<input type="radio">
支持defaultChecked
然后<select>
支持defaultValue
。
交互属性
表单组件支持一系列的props会通过用户交互影响组件。
1. value
,是<input>
和<textarea>
支持的组件。
2. checked
,是<input>
组件的checkbox
和radio
支持的
3. selected
,是<option>
组件支持的。
在HTML中,<textarea>
的值是通过子元素来设置的,在React中,需要使用value
来替代
表单组件允许通过onChange
属性的回调函数来监听修改,onChange
属性通过浏览器和用户交互的响应。
进阶技术
为什么使用受控组件
使用类似<input>
的表单组件是和传统的HTML不相同的。
<input type="text" name="title" value="Untitle">
上面的代码渲染初始化了一个value为Untitle。当用户更新输入的时候,这个节点的value属性也会改变,然而使用node.getAttribute('value')
仍然会返回初始化的时候的值:Untitled
。
与HTML不同的是,React组件必须一致保持其状态,也就是自从渲染之后,value
的值一直保持为Untitled
。
Why Textarea Value
在HTML,<textarea>
的值应该是其子元素的值。
<textarea name="description">This is the description.</textarea>
在HTML中,很容易允许开发人员提供多行的值,然而,在React中,我们不能够设置多行的字符串,如果要换行的话需要使用\n
,在有value和defaultValue的时候,因为这个原因,你不需要使用子元素来设置<textarea>
的值。
<textarea name="description" value="This is a description.">
Why Select Value
option
在<select>
中是用selected
属性来进行判断选择的,但是在React的组件中,是使用value
属性的。
<select value="B">
<option value="A">Apple</option>
<option value="B">Banana</option>
<option value="C">Cranberry</option>
</select>
使用非受控组件的话,这里需要使用defaultValue
受控输入框
class Form 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('Text field value is: ' + this.state.value);
}
render() {
return (
<div>
<input
type="text"
placeholder="edit me"
value={this.state.value}
onChange={this.handleChange}
/>
<button onClick={this.handleSubmit}>
Submit
</button>
</div>
);
}
}
ReactDOM.render(
<Form />,
document.getElementById('root')
);
受控文本区组件
class Form 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("Textarea value is: " + this.state.value);
}
render() {
return (
<div>
<textarea
name="description"
value={this.state.value}
onChange={this.handleChange}
/>
<br/>
<button onClick={this.handleSubmit}>
Submit
</button>
</div>
)
}
}
ReactDOM.render(
<Form />,
document.getElementById("root")
);
受控下拉列表
class Form 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("Select value is: " + this.state.value);
}
render() {
return (
<div>
<select value={this.state.value} onChange={this.handleChange}>
<option value="A">Apple</option>
<option value="B">Banana</option>
<option value="C">Cranberry</option>
</select>
<br/>
<button onClick={this.handleSubmit}>
Submit
</button>
</div>
)
}
}
ReactDOM.render(
<Form />,
document.getElementById("root")
);
非受控单选按钮
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
value: "B"
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({
value: event.target.value
});
}
handleSubmit(event) {
alert("Radio button value is: " + this.state.value);
}
render() {
return (
<div>
<label>
<input type="radio" name="choice" value="A" onChange={this.handleChange}/>
Option A
</label>
<label>
<input type="radio" name="choice" value="B" onChange={this.handleChange}/>
Option B
</label>
<label>
<input type="radio" defaultChecked={true} name="choice" value="C" onChange={this.handleChange}/>
Option C
</label>
<br/>
<button onClick={this.handleSubmit}>
Submit
</button>
</div>
)
}
}
ReactDOM.render(
<Form />,
document.getElementById("root")
);
非受控复选框
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
checked: {
'A': false,
'B': true,
'C': false
}
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const value = event.target.value;
const checked = Object.assign({}, this.state.checked);
if (!checked[value]) {
checked[value] = true;
} else {
checked[value] = false;
}
this.setState({checked});
}
handleSubmit(event) {
alert("Boxes checked: " +
(this.state.checked.A ? 'A ' : ' ') +
(this.state.checked.B ? 'B ' : ' ') +
(this.state.checked.C ? 'C ' : ' ')
);
}
render() {
return (
<div>
<label>
<input type="checkbox" value="A" onChange={this.handleChange} />
Option A
</label>
<label>
<input type="checkbox" value="B" onChange={this.handleChange} defaultChecked={true}/>
Option B
</label>
<label>
<input type="checkbox" value="C" onChange={this.handleChange} />
Option C
</label>
<button onClick={this.handleSubmit}>
Submit
</button>
</div>
)
}
}
ReactDOM.render(
<Form />,
document.getElementById("root")
);