六、表单
表单元素在React中自身维护一些状态,这些状态默认情况下是不受react控制的,这类状态不受react控制的表单元素称为非受控组件。
在React中,状态的修改必须通过组件的state,非受控组件有悖于这一原则,为了让表单元素的状态变更也能通过组件的state管理,React使用受控组件的技术达到这一目的。
1,受控组件
如果一个表单元素的值是由React来管理的,那么它就是一个受控组件。对于不同的表单元素,React的控制方法略有不同,常用的三类表单元素控制方式是:
①文本框
包含类型为text的input和textarea元素,它们受控的原理是:通过value属性设置表单元素的值,通过onChange时间监听值的变化,并将变化同步到React组件的state中:
class LoginForm extends Component {
constructor() {
this.state = {
name: '',
password: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
const target = e.target;
this.setState({
[target.name]: target.value
})
}
handleSubmit(e) {
e.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
用户名:
<input type="text" name="name" value={this.state.name} onChange={this.handleChange} />
</label>
<label>
密码:
<input type="password" name="name" value={this.state.password} onChange={this.handleChange} />
</label>
<input type="submit" value="登录" />
</form>
)
}
}
export default LoginForm;
②列表
React通过在select上定义value属性来决定哪一个option处于选中状态。
class LoginForm extends Component {
constructor() {
this.state = {
value: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
const target = e.target;
this.setState({
value: target.value
})
}
handleSubmit(e) {
e.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
列表:
<select value={this.state.value} onChange={this.handleChange}>
<option value="react">react</option>
<option value="redux">redux</option>
</select>
</label>
<input type="submit" value="登录" />
</form>
)
}
}
export default LoginForm;
③复选框和单选框
React控制checked属性
class LoginForm extends Component {
constructor() {
this.state = {
react: false,
redux: false
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
const target = e.target;
this.setState({
[target.name]: target.checked
})
}
handleSubmit(e) {
e.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
react:
<input type="checkbox" name="react" value="react" checked={this.state.react} onChange={this.handleChange} />
</label>
<label>
redux:
<input type="checkbox" name="redux" value="redux" checked={this.state.redux} onChange={this.handleChange} />
</label>
<input type="submit" value="登录" />
</form>
)
}
}
export default LoginForm;
2,,非受控组件
表单元素的状态依然由表单元素自己管理,React提供了一个特殊的属性ref,用来引用React组件或DOM元素的实例。
class LoginForm extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e) {
console.log(this.input.value);
e.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
title:
<input type="text" ref={(input) => this.input = input} />
</label>
<input type="submit" value="登录" />
</form>
)
}
}
export default LoginForm;
ref的值是一个函数,接收当前元素作为参数,上述例子中input参数指向的是当前元素,把input赋值给this.input,进而可以在组件的其他地方通过this.input获取这个元素。
使用非受控组件时,常常需要为相应的表单元素设置默认值,但无法通过value设置,因为React无法控制表单元素的value属性,一旦在非受控组件中定义了value属性的值,就很难保证后续表单元素的值的正确性。这种情况下,我们可以使用defaultValue属性指定默认值:
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
title:
<input defaultValue="something" type="text" ref={(input) => this.input = input} />
</label>
<input type="submit" value="登录" />
</form>
)
}
select元素和textarea元素也支持通过defaultValue设置默认值,checkbox和radio支持通过defaultChecked设置默认值。
非受控组件破坏了React对组件管理的一致性,往往容易出现不容易排查的问题,非特殊情况下,不使用。