“表单虽小,乾坤很大。”
在 React 的世界里,表单就像是一场舞台剧。有的演员(组件)严格按照剧本(状态)走位,一丝不苟;有的则自由发挥,临场即兴,只在关键时刻才汇报演出成果。
今天,我们就来聊聊这场精彩对决——受控组件 vs 非受控组件,看看谁更适合你的项目舞台!
🧙♂️ 什么是“受控”?什么是“非受控”?
🔒 受控组件(Controlled Component):状态说了算!
想象你是个霸道总裁,表单就是你的秘书。
你让她写什么,她就写什么;她想改一个字?必须先打报告(onChange),你批准(setState)后才能改。
const [value, setValue] = useState("");
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
-
特点:表单的值完全由 React 状态(state)控制。
-
优点:
- 实时校验(比如密码强度提示)
- 多字段联动(选城市自动更新区县)
- 值始终可预测,调试友好
-
缺点:代码略多,每个输入都要绑定
value和onChange
💡 适合场景:登录注册、复杂表单、需要实时反馈的交互。
🕶️ 非受控组件(Uncontrolled Component):DOM 自己管自己!
这次你放权了,让秘书自由发挥。
你只在最后提交时问一句:“你写了啥?”——她直接从草稿纸上念给你听(通过 ref 读取 DOM 值)。
const inputRef = useRef(null);
const handleSubmit = () => {
console.log(inputRef.current.value); // 直接读 DOM!
};
<input ref={inputRef} />
-
特点:表单数据由 DOM 自身管理,React 不干预。
-
优点:
- 代码简洁,无需为每个字段写状态
- 性能略优(少一次 re-render)
- 特别适合一次性读取的场景(如评论、文件上传)
-
缺点:
- 无法实时监听变化
- 难以做动态校验或联动
- “黑盒”操作,不利于测试和维护
💡 适合场景:简单评论框、搜索框、文件上传、性能敏感型应用。
🎭 实战对比:谁更胜一筹?
场景一:用户登录(需要校验 + 联动)
// ✅ 受控组件:完美胜任
const [form, setForm] = useState({ username: "", password: "" });
const handleChange = (e) => {
setForm({ ...form, [e.target.name]: e.target.value });
};
return (
<form>
<input name="username" value={form.username} onChange={handleChange} />
<input name="password" value={form.password} onChange={handleChange} />
<button disabled={!form.username || !form.password}>登录</button>
</form>
);
这里你能实时禁用按钮、高亮错误、甚至根据用户名自动填充邮箱——受控组件,YYDS!
场景二:用户评论(写完就提交,无需中间逻辑)
// ✅ 非受控组件:轻装上阵
const textareaRef = useRef();
const handleSubmit = () => {
const comment = textareaRef.current.value;
if (!comment) return alert("说点啥吧!");
sendComment(comment);
};
return (
<div>
<textarea ref={textareaRef} placeholder="写下你的神评..." />
<button onClick={handleSubmit}>发射!</button>
</div>
);
没有状态、没有
onChange、没有烦恼。干净利落,像极了爱情(?)
⚠️ 常见误区 & 小贴士
- 拼写错误是魔鬼!
textareaRef.current.vuale→ 正确是.value!
(别笑,这行代码来自真实事故现场 😭) - 不要混用!
同一个 input 既用value={state}又想用ref.current.value?
React 会警告你:“你到底想让我控制还是不控制?” - 文件上传只能是非受控!
<input type="file" />的value是只读的,必须用ref获取文件。 - 性能真的差很多吗?
对于普通表单,几乎没区别。除非你有成百上千个输入框(那你该考虑分页了😅)。
🎯 如何选择?一张表搞定!
| 场景 | 推荐方案 |
|---|---|
| 需要实时校验/格式化 | ✅ 受控 |
| 多字段联动(如省市区) | ✅ 受控 |
| 简单评论/搜索 | ✅ 非受控 |
| 文件上传 | ✅ 非受控 |
| 表单复杂度高 | ✅ 受控(或用 Formik/Zod) |
| 追求极致性能(且逻辑简单) | ✅ 非受控 |
🌟 终极建议:默认用受控,特殊场景用非受控
React 官方也推荐:尽可能使用受控组件。
因为 React 的核心哲学就是——状态驱动 UI。让数据流清晰、可预测,才是长久之道。
但如果你只是想快速搞个评论框,又不想写一堆 useState,那非受控组件就是你的“快捷键”。
🎉 结语:表单无小事,选择需谨慎
受控组件像“直升机父母”,事无巨细都要管;
非受控组件像“放养式教育”,结果导向,过程自由。
没有绝对的好坏,只有合适的场景。
下次写表单前,不妨问问自己:
“我需要实时掌控,还是只要最终答案?”
答案出来,选择自然清晰。