我们可以通过使 React 的 state 成为 “单一数据源原则” 来结合这两个形式。然后渲染表单的 React 组件也可以控制在用户输入之后的行为。这种形式,其值由 React 控制的输入表单元素称为“受控组件”。
总的来说,< input type=”text”>, < textarea> 和 < select> 工作方式都类似 —— 它们都接受一个 value 属性可以用来实现一个受控组件
。
看下面例子:
由于 value 属性设置在我们的表单元素上,显示的值总是 this.state.value,以满足 state 状态的同一数据理念。 handleChange 在每次敲击键盘时运行,以更新 React state(状态),显示的值将更新为用户的输入。
class NameForm extends React.Component {
constructor(props){
super(props);
this.state = {value:''};
}
handleChange = (e) => {
this.setState({
value: e.target.value
});
//这样是错的:this.setState(() => ({value:e.target.value }));
}
handleSubmit = (e) => {
alert('input value is : ' + this.state.value);
e.preventDefault();
}
render(){
return(
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
对于受控组件来说,每一次 state(状态) 变化都会伴有相关联的处理函数。这使得可以直接修改或验证用户的输入。比如,如果我们希望强制 name 的输入都是大写字母,可以这样来写 handleChange 方法:
//效果:在键盘输入任意字母,input里显示出来的是大写字母
handleChange(e) {
this.setState({value: e.target.value.toUpperCase()});
}
在 HTML 中,< textarea> 元素通过它的子节点定义了它的文本值:
在 React 中,< textarea> 的赋值使用 value 属性替代
。这样一来,表单中 < textarea> 的书写方式接近于单行文本输入框
:
例:
class EssayForm extends React.Component {
constructor(props){
super(props);
this.state = {
value:'Please write an essay'
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e){
this.setState({
value: e.target.value
});
}
handleSubmit(e){
alert('input value is : ' + this.state.value);
e.preventDefault();
}
render(){
return(
);
}
}
在 HTML 中,< select> 创建了一个下拉列表。例如,这段 HTML 创建一个下拉列表:
在React 中,并不使用这个 selected 属性,而是在根 select 标签中使用了一个 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(e){
this.setState({
value: e.target.value
});
}
handleSubmit(e){
alert('you selected value is : ' + this.state.value);
e.preventDefault();
}
render(){
return(
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
效果:(默认coconut被选中)
选择‘mango’,点击‘submit’后,
注意:
您可以将一个数组传递给 value 属性,允许你在 select 标签中选择多个选项:
在HTML中, < input type=”file”> 可以让用户从设备存储器中选择一个或多个文件上传到服务器,或者通过 JavaScript 使用 File API 操作。
type="file" />
在 React 中, 和一个普通的 < input /> 类似,但有一个重要的区别:它是只读的(您不能以编程方式设置值)。相反,你应该使用 File API 与文件进行交互。
以下示例显示了如何使用一个 ref 来访问提交处理程序中的文件:
class FileInput extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
event.preventDefault();
alert(`Selected file - ${this.fileInput.files[0].name}`);
}
render() {
return (
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
当您需要处理多个受控的 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 (
);
}
}
ReactDOM.render(
,
document.getElementById('root')
);
输出效果:点击我
注意我们如何使用ES6计算的 属性名称语法 来更新与给定输入名称相对应的 state(状态) 键:
this.setState({
[name]: value
});
这段代码等价于 ES5 代码:
var partialState = {};
partialState[name] = value;
this.setState(partialState);
下面这段代码,不能编辑 input的值
ReactDOM.render(
type='text' value="hi" />,
document.getElementById('root')
);
但下面这段代码 可以编辑 input里的值
ReactDOM.render(
type='text' value={null} />,
document.getElementById('root')
);
受控组件的替代方案:
有时使用受控组件有些乏味,因为你需要为每一个可更改的数据提供事件处理器,并通过 React 组件管理所有输入状态。当你将已经存在的代码转换为 React 时,或将 React 应用程序与非 React 库集成时,这可能变得特别烦人。在这些情况下,您可能需要使用不受控的组件,用于实现输入表单的替代技术。