React 表单界的宫斗大戏:受控组件 VS 非受控组件,谁才是正宫娘娘?

------ 小白都能看懂的 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" />

高阶开发者常用组合拳:受控 + 非受控混合用!

比如你可以:

  • 用受控组件处理 usernamepassword 等字段
  • 用非受控组件上传头像(因为 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 知识点?欢迎评论区许愿!我下一篇写给你!

相关推荐
东东2331 分钟前
前端开发中如何取消Promise操作
前端·javascript·promise
掘金安东尼6 分钟前
官方:什么是 Vite+?
前端·javascript·vue.js
柒崽8 分钟前
ios移动端浏览器,vh高度和页面实际高度不匹配的解决方案
前端
渣哥24 分钟前
你以为 Bean 只是 new 出来?Spring BeanFactory 背后的秘密让人惊讶
javascript·后端·面试
烛阴32 分钟前
为什么游戏开发者都爱 Lua?零基础快速上手指南
前端·lua
大猫会长42 分钟前
tailwindcss出现could not determine executable to run
前端·tailwindcss
Moonbit1 小时前
MoonBit Pearls Vol.10:prettyprinter:使用函数组合解决结构化数据打印问题
前端·后端·程序员
533_1 小时前
[css] border 渐变
前端·css
云中雾丽1 小时前
flutter的dart语言和JavaScript的消息循环机制的异同
前端
地方地方1 小时前
Vue依赖注入:provide/inject 问题解析与最佳实践
前端·javascript·面试