受控 vs 非受控组件,React 表单到底怎么写才对?一文全懂!

89 阅读3分钟

在 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} />
    </>
  )
}

image.png

你会发现:

  • 受控组件会在你输入时实时检测字符长度。
  • 非受控组件只有点“提交”之后,才拿到值。

✅实际开发怎么选?

一句话总结:

如果表单需要交互强实时验证动态显示错误信息,就用受控组件
如果只是简单收集一个输入框的值,非受控组件更轻量、性能更好

比如:

  • 搜索框、留言板 👉 非受控更合适
  • 注册、修改密码、复杂校验表单 👉 受控组件更稳

📌最后

React 并不强制你只能使用受控或非受控,选对场景比死记 API 更重要

希望这篇文章能帮你真正理解这两种写法,而不是只是照着写代码。如果对你有帮助,欢迎点赞、收藏和转发~👊