------ 小白都能看懂的 React 表单真相
嗨,大家好,我是一个刚入 React 不久、但已经在表单世界里被 state 和 ref 搅得头昏脑涨的前端小白。
今天这篇文章,我来给你讲清楚一个在 React 面试中出镜率极高、开发中经常用到,但却让很多初学者绕晕的概念:
"受控组件(Controlled) VS 非受控组件(Uncontrolled)"!
一句话版理解
- 受控组件 :你输入的值,React 全程都知道,一切尽在掌控。
- 非受控组件 :你输入的值,React 不过问,值藏在 DOM 自己肚子里 ,你需要用
ref
去问它。
就像一对情侣:
- 受控组件 = "你去哪我都知道"型恋人(state 控制)
- 非受控组件 = "你去哪我不管"型恋人(ref 读取)
🍜 来一碗小白友好的"代码实战拉面"
我们写两个输入框,一个是受控,一个是非受控
受控组件版本
jsx
function ControlledInput({ onSubmit }) {
const [value, setValue] = useState('');
const [error, setError] = useState('');
const handleChange = (e) => {
const newValue = e.target.value;
setValue(newValue);
setError(newValue.length < 6 ? '请输入6个字符以上' : '');
};
const handleSubmit = (e) => {
e.preventDefault();
onSubmit(value);
};
return (
<form onSubmit={handleSubmit}>
<label>受控组件</label>
<input value={value} onChange={handleChange} required />
{error && <p>{error}</p>}
<input type="submit" value="提交" />
</form>
);
}
总结一下受控组件的"人设":
- 每输入一个字,就立马调用
setValue
- 输入框内容 = React state 中的值
- 优势:你可以实时校验、动态反馈
- 缺点:每打一个字就重新渲染,表单多时可能性能差点,需要优化(比如防抖)
非受控组件版本
jsx
function UncontrolledInput({ onSubmit }) {
const inputRef = useRef();
const handleSubmit = (e) => {
e.preventDefault();
const value = inputRef.current.value;
onSubmit(value);
};
return (
<form onSubmit={handleSubmit}>
<label>非受控组件</label>
<input ref={inputRef} />
<input type="submit" value="提交" />
</form>
);
}
非受控组件的"人设":
- React 不插手输入框的值
- 想要用就用
ref.current.value
去 DOM 拿 - 优势:代码简单、性能更好
- 缺点:表单验证、联动很麻烦,不太"React 风格"
受控 vs 非受控,总结对比表来了!
对比点 | 受控组件 | 非受控组件 |
---|---|---|
值存储在哪? | React 的 state | DOM 的 input 元素里 |
如何获取值? | 通过 state | 通过 ref.current.value |
是否可校验? | ✅ 非常适合 | ❌ 需要手动做 |
是否响应式? | ✅ 一输值就刷新 | ❌ React 不知道值变了 |
性能开销 | 会频繁触发 re-render | 性能好,React 几乎不介入 |
推荐场景 | 注册/编辑等复杂表单 | 文件上传、搜索框、简单提交 |
代码风格 | 正统 React 哲学 | 偏向 DOM 操作 |
官方到底推荐哪个?
React 官方文档建议:"优先使用受控组件。"
因为 React 的核心理念是:数据驱动视图,你希望所有状态都"在自己掌控之中"。
但这不是说非受控组件就不好,它们非常适合:
- 一次性提交表单
- 性能敏感的页面
- 文件上传组件(
<input type="file" />
)
高阶开发者常用组合拳:受控 + 非受控混合用!
比如你可以:
- 用受控组件处理
username
、password
等字段 - 用非受控组件上传头像(因为 file input 无法受控)
rust
<input type="file" ref={fileRef} /> // 非受控
性能优化加餐:受控组件的防抖处理
受控组件太"敏感",你每敲一个字就会触发更新,可以用 lodash 的 debounce
优化:
js
const debouncedChange = debounce((e) => {
setValue(e.target.value);
}, 300);
<input onChange={debouncedChange} />
这就像给它戴上了"情绪稳定器",不至于一敲字就刷屏更新。
最后给你一份总结口诀(写简历/面试能用)
「受控由我控,状态同步通;非控图轻松,DOM 自成风。 」
或者:
「复杂交互用受控,性能优先用非控。校验强就受控,简单值用 ref 拿走。」
📌 写在最后
受控和非受控的区别,说到底是你要不要掌控 input 的值。
- 想自己掌控全局,React 说了算 → 就用受控组件
- 想轻量快速,别打扰我输入 → 就用非受控组件
无论你是初学者还是资深选手,理解这两个概念对你写出健壮、高性能、可维护的表单系统都至关重要!
如果你觉得本文对你有帮助,欢迎点赞 👍 + 收藏 ⭐ + 关注我!
我会持续更新更多 React 初学者也能轻松读懂的"大厂底层知识"解析系列~
你还想我讲哪个 React 知识点?欢迎评论区许愿!我下一篇写给你!