React JS中输入框为何需用onChange事件而非提交时统一更新state
首先明确一点:提交时再统一获取输入值的写法完全可行,不存在不能用的问题,React本身没有强制要求必须给输入框绑定onChange做实时state更新,两种写法各有适用场景。
两种表单实现模式的本质区别
React里的表单输入本来就分两种实现思路:
- 非受控组件:输入框的状态完全存在浏览器DOM内部,你不需要实时同步state,等提交的时候通过ref或者FormData API从DOM节点上拿值就行,比如下面这种写法是完全能正常跑的:
function SimpleLoginForm() { const handleSubmit = (e) => { e.preventDefault() // 直接从表单实例里拿所有带name属性的输入值 const formData = new FormData(e.target) const username = formData.get('username') const password = formData.get('password') // 走后续提交逻辑 } return ( <form onSubmit={handleSubmit}> <input name="username" placeholder="用户名" /> <input name="password" type="password" placeholder="密码" /> <button type="submit">登录</button> </form> ) }
- 受控组件:输入框的value完全和React state绑定,每次输入触发onChange的时候更新state,输入框显示什么内容完全由state决定,也就是你问题里提到的常规写法。
为什么大多数场景下大家更推荐受控组件
非受控组件虽然写起来省代码,但短板非常明显,只要表单稍微复杂一点就会很难维护:
- 没法支持输入过程中的实时交互:比如实时校验输入格式、输入时展示搜索联想、字符数计数、输入内容实时预览、根据当前输入值动态显示/隐藏其他表单项,这些需求都要求你在用户输入的当下就拿到最新值,等点提交再拿值根本实现不了。
- 状态同步成本高:受控模式下表单值全存在React state里,你要做表单重置、值回填、多步骤表单值透传,只要修改state就行,输入框会自动同步显示对应内容。如果是非受控模式,你得挨个拿到每个输入框的DOM引用,手动修改DOM的value属性,逻辑散落在各处很容易出bug,出现DOM显示的值和你业务逻辑里存的值不一致的问题。
- 输入拦截处理麻烦:如果要限制用户只能输入数字、自动格式化输入内容(比如手机号自动加分隔符、身份证号自动加空格)、拦截敏感词输入,在onChange里处理是最顺畅的,用户输入的时候直接就把不符合规则的内容过滤掉,不用等用户填完所有内容点提交了才弹提示让修改。
每次输入都更新state会不会有性能问题
绝大多数场景下完全不用担心。React本身对状态更新做了批处理,用户输入时每次敲字触发的setState不会导致页面反复全量重渲染,只会更新依赖这个表单值的相关组件,普通规模的表单这点重渲染开销用户根本感知不到。真遇到超大型表单、组件重渲染逻辑特别复杂的场景,也可以通过拆分表单状态、给无关组件加memo缓存、用延迟更新等方式优化,没必要因为这点顾虑放弃受控组件的可维护性。
实际开发里完全不用死磕某一种写法,简单静态表单用非受控写法省代码没问题,带复杂交互的表单用受控模式维护性更高,选适配场景的方案就行。
内容的提问来源于stack exchange,提问作者viru jamwal
相关产品推荐
相关产品推荐

