原文:(https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/)
你也许在很多文章中看到过说“you shouldn’t use setState…”或者声称“refs are bad”…这是很矛盾的事。这让我们很难理解怎么才能正确取值甚至说选择的标准到底是什么。
你会认为到底应该怎么操作表单?
毕竟,表单事很多web应用程序的核心。并且,react中操作表单似乎是一种基础操作?
不要担心,让我告诉你这些方法之间的差异,以及应该如何使用。
非受控组件
非受控组件的输入框类似于传统的表单输入
class Form extends Component {
render() {
return (
<div>
<input type="text" />
</div>
);
}
}
它能够记住你输入了什么,你可以使用一个ref来获取它的值。例如,一个按钮的onClick
操作:
class Form extends Component {
handleSubmitClick = () => {
const name = this._name.value;
}
render() {
return (
<div>
<input type="text" ref={input => this._name = input} />
<button onClick={this.handleSubmitClick}>Sign up</button>
</div>
);
}
}
不同的是,当你需要的时候,你就必须从这个区域里“拉取”值。通常发生在表单提交的时候。
这是实现表单输入的最简单的方式。在现实世界中学习使用react操作简单的表单时,这无疑是一个很有效的使用方法。
不过,它没有那么强大,让我们接下来看看受控组建的输入表单。
受控组件
一个受控组件接受当前的值作为参数,并且在值发生改变的时候执行回调函数。你可以说这是一种更接近的“react 方法”(这并不意味着你应该一直使用它)。
<input value={someValue} onChange={handleChange} />
这样没有问题,但是input的值必须是存在的state。通常来说,渲染成input框的组件(即表单组件)就保存在它的state中:
(当然,那也可以是另一个组件的state,甚至独立存在于状态储存中,比如说redux
。)
class From extends Component {
constructor(){
super();
this.state = {
name: ''
}
}
handleNameChange = (event) => {
this.setState({name: event.target.value })
}
render(){
return (
<div>
<input
type="text"
value={this.state.name}
onChange={this.handleNameChange}
/>
</div>
);
}
}
每次你键入了一个新的字符,就会调用handleNameChange
。它会获取input最新的值并在state中设置。
- 开始设置值为空字符串—
''
- 你输入一个
a
,然后执行handleNameChange
获得a
并且设置了setState
,然后input输入框a
被重新渲染 - 你继续键入
b
,handleNameChange
获得ab
并且设置state
,input输入框再次被重新渲染,现在的值是value=ab
这种“推入式”的流程改变了表单控件,因此表单控件总是能够一直获取输入框当前的值,而不用明确知道对象是谁。
这意味着你的数据state
以及UIinput
总是异步的。状态将值赋給输入框,输入框通知表单改变当前的值。
这也意味着输入框发生变化时表单组件能够及时响应;例如:
- 就地反馈,例如验证
- 禁用按钮,除非所有字段都是有效数据
- 执行特定的输入格式,例如信用卡号码
但是如果你并不需要这些,认为不受控组件更简单一点,那就用不受控组件吧。
什么使元素“受控”
当然,还有其他的表单元素。你可以使用checkboxes
、radios
以及selects
、textareas
如果你通过参数来设置表单元素的值,就可以让它成为“受控组件”,就这么简单。
不过,每个表单元素都有一个不同的支持来设置该值,所以这里有一个小表来总结:
Element | Value property | Change callback | New value in the callback |
---|---|---|---|
<input type="text" /> |
value="string" |
onChange |
event.target.value |
<input type="checkbox" /> |
value={boolean} |
onChange |
event.target.checked |
<input type="radio" /> |
value={boolean} |
onChange |
event.target.checked |
<textarea/> |
value="string" |
onChange |
event.target.value |
<select/> |
value="option value" |
onChange |
event.target.value |
结论
受控和不受控表单字段都有它们的优点。评估你的具体情况并选择最合适的—对你最有效的方法就足够了。
如果你的表单在UI反馈方面极其简单,不受控的参考时完全合适的。你不需要听从许多文章说这是不好的。
feature | uncontrolled | controlled |
---|---|---|
一次性检索提交(例如submit ) |
✅ | ✅ |
字段即时验证 | ❌ | ✅ |
有条件的禁用提交按钮 | ❌ | ✅ |
强制输入的格式 | ❌ | ✅ |
一段数据分多个输入框 | ❌ | ✅ |
动态输入 | ❌ | ✅ |