在 React 项目中,表单几乎无处不在:登录、注册、搜索、评论……但你有没有注意到,React 表单有两种写法 —— 受控组件 和 非受控组件。
很多刚入门的同学一开始都会有点懵:两种写法到底有什么区别?我应该用哪一种?性能差异大不大?是不是只有受控才是“推荐方式”?
这篇文章就用最简单的代码,帮你彻底搞懂这两种写法的核心区别、优缺点,以及在实际项目中该怎么选。
🧩什么是受控组件?
“受控组件”就是:输入框的值受 React 的状态(state)控制,也就是说,React 管着输入框。
来看一段代码就明白了:
function ControlledInput({ onSubmit }) {
const [value, setValue] = useState('')
const [error, setError] = useState('')
const handleChange = (e) => {
setValue(e.target.value)
if (e.target.value.length < 6) {
setError('输入内容不能小于6个字符')
} else {
setError('')
}
}
const handleSubmit = (e) => {
e.preventDefault()
onSubmit(value)
}
return (
<form onSubmit={handleSubmit}>
<label>受控组件</label>
<input
type="text"
value={value}
onChange={handleChange}
required
/>
{error && <p>{error}</p>}
<input type="submit" value="提交" />
</form>
)
}
✅ 优点:
- 表单值始终和
value状态同步,React 能随时掌控。 - 可以做实时校验、条件渲染,比如输入不合格就显示错误提示。
- 适合需要复杂交互的表单,比如登录注册、动态验证、输入联动等。
⚠️注意:
- 每次输入都会触发一次
setState,如果输入很频繁可能有点性能压力(可以用防抖优化)。
🔍什么是非受控组件?
“非受控组件”则是另一种思路:不把输入框的值交给 React 管,而是交给 DOM 本身。
举个例子:
function UncontrolledInput({ onSubmit }) {
const inputRef = useRef(null)
const handleSubmit = (e) => {
e.preventDefault()
const value = inputRef.current.value
onSubmit(value)
}
return (
<form onSubmit={handleSubmit}>
<label>非受控组件</label>
<input
type="text"
ref={inputRef}
/>
<input type="submit" value="提交" />
</form>
)
}
✅ 优点:
- 不需要用
useState来保存值,减少不必要的渲染。 - 代码更简单,性能更好,适合表单内容不复杂、交互要求不高的场景。
⚠️注意:
- 不能做实时校验,因为值是保存在 DOM 中的,不在 React 的控制之下。
- 获取输入值只能通过
ref方式,一般是在提交的时候才拿。
🆚两者对比一览表
| 对比点 | 受控组件 | 非受控组件 |
|---|---|---|
| 数据来源 | React 状态(state) | DOM 节点(ref) |
| 是否实时同步 | 是 | 否(提交时读取) |
| 适合场景 | 复杂交互、实时校验 | 简单输入、性能优先 |
| 代码复杂度 | 稍高 | 较低 |
💡实战演示:怎么选?
我们在 App 组件里同时使用这两个表单,你可以在控制台看到它们各自提交的效果:
function App() {
const handleSubmit = (value) => {
console.log(value, '用户提交的数据')
}
return (
<>
<ControlledInput onSubmit={handleSubmit} />
<UncontrolledInput onSubmit={handleSubmit} />
</>
)
}
你会发现:
- 受控组件会在你输入时实时检测字符长度。
- 非受控组件只有点“提交”之后,才拿到值。
✅实际开发怎么选?
一句话总结:
如果表单需要交互强、实时验证、动态显示错误信息,就用受控组件;
如果只是简单收集一个输入框的值,非受控组件更轻量、性能更好。
比如:
- 搜索框、留言板 👉 非受控更合适
- 注册、修改密码、复杂校验表单 👉 受控组件更稳
📌最后
React 并不强制你只能使用受控或非受控,选对场景比死记 API 更重要。
希望这篇文章能帮你真正理解这两种写法,而不是只是照着写代码。如果对你有帮助,欢迎点赞、收藏和转发~👊