一文讲清 React 表单中受控与非受控输入(译)你可能看到过很多文章都在说“你不应该使用 setState”,而文档上
原文:Controlled and uncontrolled form inputs in React don't have to be complicated
你可能看到过很多文章都在说“你不应该使用 setState
”,而文档上却说“refs
是坏的”……这太矛盾了。很难理解如何“做对”,甚至是什么标准来选择。
你该怎么做表单呢?
毕竟,表单是很多网页应用程序的核心。然而,在React中处理表单似乎有点……基础?
别怕。让我向你展示这些方法之间的区别,以及什么时候应该使用每种方法。
非受控组件(The Uncontrolled)
非受控输入就像传统的HTML表单输入:
class Form extends Component {
render() {
return (
<div>
<input type="text" />
</div>
);
}
}
他们记住你输入的内容。你可以用ref
来获取它们的值。例如,在按钮的onClick
处理程序中:
class Form extends Component {
handleSubmitClick = () => {
const name = this._name.value;
// 处理 `name`
};
render() {
return (
<div>
<input type="text" ref={(input) => (this._name = input)} />
<button onClick={this.handleSubmitClick}>Sign up</button>
</div>
);
}
}
换句话说,**你需要在需要的时候从字段中“提取”值。**这可以在表单提交时发生。
这是实现表单输入的最简单方法。当然,在现实世界中的简单表单和学习React时,这种方法是有效的。
不过它并不是那么强大,所以接下来让我们看看那些受控输入。
小结: 非受控组件不使用 state 而是使用简单有效的 ref ,仅从字段中提取值,适用于表单逻辑不复杂的情况。
受控组件
受控输入接受其当前值作为属性,并接受一个回调函数来更改该值。 可以说,这是更“React方式”的方法(这并不意味着你总是应该使用它)。
<input value={someValue} onChange={handleChange} />
这样也不错……但是这个输入的值必须存储在某个状态(state)中。通常,渲染输入的组件(即表单组件)会在其状态(state)中保存该值:
class Form 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>
);
}
}
(当然,它也可以在另一个组件的状态中,或者甚至在单独的状态存储中,如Redux。)
每次你输入一个新字符时,handleNameChange
都会被调用。它接受输入的新值并将其设置在状态中。
- 它开始是一个空字符串——
''
。 - 你输入
a
,handleNameChange
获取到a
并调用setState
。然后输入被重新渲染,值为a
。 - 你输入
b
,handleNameChange
获取到值ab
并设置到状态中。输入再次重新渲染,现在值为"ab"
。
这种流程“推送”值的变化到表单组件,因此表单组件总是有输入的当前值,而不需要明确的请求。
这意味着你的数据(状态)和UI(输入)总是同步的。状态赋予输入值,输入请求表单组件更改当前值。
这还意味着表单组件可以立即响应输入更改;例如,通过:
- 即时反馈,如验证
- 除非所有字段都有有效数据,否则禁用按钮
- 强制要求特定输入格式,如信用卡号码
但如果你不需要这些,并且认为非受控的更简单,那就用它吧。
小结:受控组件定义 state 对值进行存储,其数据和 UI 同步,这让我们可以控制状态更新的逻辑,如添加校验等。
元素何时受控
当然还有其他表单元素。你有复选框、单选按钮、选择框和文本区域。
如果通过属性设置其值,表单元素就变成“受控”的。就是这样。
每个表单元素都有不同的属性来设置值,所以这里有一个小表格来总结:
元素 | 值属性 | Change callback(回调) | New value in the callback(回调中新值) |
---|---|---|---|
<input type="text" /> | value="string" | onChange | event.target.value |
<input type="checkbox" /> | checked={boolean} | onChange | event.target.checked |
<input type="radio" /> | checked={boolean} | onChange | event.target.checked |
<textarea /> | value="string" | onChange | event.target.value |
<select /> | value="option value" | onChange | event.target.value |
结论
受控和非受控表单字段各有优势。评估你的具体情况并选择合适的方法——适合你的方法就是好方法。
如果你的表单在UI反馈方面非常简单,用ref的非受控方式完全没问题。你不必听信各种文章说什么是“坏的”。
特性 | 非受控 | 受控 |
---|---|---|
一次性值检索(例如提交时) | ✅ | ✅ |
提交时验证 | ✅ | ✅ |
即时字段验证 | ❌ | ✅ |
有条件地禁用提交按钮 | ❌ | ✅ |
强制输入格式 | ❌ | ✅ |
多个输入对应一个数据 | ❌ | ✅ |
动态输入 | ❌ | ✅ |
此外,这不是一次性的决定:你可以随时迁移到受控输入。从非受控到受控输入的迁移并不难。
转载自:https://juejin.cn/post/7422660569257213990