news 2026/6/10 18:50:09

受控组件 vs 非受控组件

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
受控组件 vs 非受控组件

核心区别

受控组件 (Controlled Components)

由 React 完全控制,表单数据由 React 组件的 state 管理。

非受控组件 (Uncontrolled Components)

由 DOM 自身管理,通过 ref 获取表单值。

详细对比

特性受控组件非受控组件
数据管理React stateDOM
值更新onChange事件 +setState用户直接输入
获取值state.valueref.current.value
初始化值value属性defaultValue属性
表单提交从 state 获取从 ref 获取
实时验证容易实现较难实现
即时反馈立即更新 UI需要手动触发

代码示例

1.受控组件示例

import React, { useState } from 'react'; const ControlledForm = () => { const [formData, setFormData] = useState({ name: '', email: '', age: '' }); const handleChange = (e) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value })); }; const handleSubmit = (e) => { e.preventDefault(); console.log('表单数据:', formData); }; return ( <form onSubmit={handleSubmit}> <div> <label>姓名:</label> <input type="text" name="name" value={formData.name} onChange={handleChange} /> </div> <div> <label>邮箱:</label> <input type="email" name="email" value={formData.email} onChange={handleChange} /> </div> <div> <label>年龄:</label> <input type="number" name="age" value={formData.age} onChange={handleChange} /> </div> <button type="submit">提交</button> </form> ); };

2.非受控组件示例

import React, { useRef } from 'react'; const UncontrolledForm = () => { const nameRef = useRef(null); const emailRef = useRef(null); const ageRef = useRef(null); const handleSubmit = (e) => { e.preventDefault(); const formData = { name: nameRef.current.value, email: emailRef.current.value, age: ageRef.current.value }; console.log('表单数据:', formData); }; return ( <form onSubmit={handleSubmit}> <div> <label>姓名:</label> <input type="text" name="name" ref={nameRef} defaultValue="" // 初始化值 /> </div> <div> <label>邮箱:</label> <input type="email" name="email" ref={emailRef} defaultValue="" /> </div> <div> <label>年龄:</label> <input type="number" name="age" ref={ageRef} defaultValue="" /> </div> <button type="submit">提交</button> </form> ); };

使用场景对比

适合使用受控组件的场景:

// 1. 需要实时验证 const ValidatedInput = () => { const [value, setValue] = useState(''); const [error, setError] = useState(''); const handleChange = (e) => { const val = e.target.value; setValue(val); // 实时验证 if (val.length < 3) { setError('至少需要3个字符'); } else { setError(''); } }; return ( <div> <input value={value} onChange={handleChange} style={{ borderColor: error ? 'red' : 'gray' }} /> {error && <div style={{ color: 'red' }}>{error}</div>} </div> ); }; // 2. 表单联动 const DependentFields = () => { const [country, setCountry] = useState(''); const [cities, setCities] = useState([]); const [selectedCity, setSelectedCity] = useState(''); const countries = { china: ['北京', '上海', '广州'], usa: ['纽约', '洛杉矶', '芝加哥'] }; const handleCountryChange = (e) => { const selected = e.target.value; setCountry(selected); setCities(countries[selected] || []); setSelectedCity(''); // 重置城市选择 }; return ( <div> <select value={country} onChange={handleCountryChange}> <option value="">选择国家</option> <option value="china">中国</option> <option value="usa">美国</option> </select> <select value={selectedCity} onChange={(e) => setSelectedCity(e.target.value)} disabled={!cities.length} > <option value="">选择城市</option> {cities.map(city => ( <option key={city} value={city}>{city}</option> ))} </select> </div> ); };

适合使用非受控组件的场景:

// 1. 文件上传 const FileUpload = () => { const fileRef = useRef(null); const handleSubmit = (e) => { e.preventDefault(); console.log('文件:', fileRef.current.files[0]); }; return ( <form onSubmit={handleSubmit}> <input type="file" ref={fileRef} /> <button type="submit">上传</button> </form> ); }; // 2. 简单表单,不需要实时验证 const SimpleForm = () => { const formRef = useRef(null); const handleSubmit = (e) => { e.preventDefault(); const formData = new FormData(formRef.current); const data = Object.fromEntries(formData); console.log(data); }; return ( <form ref={formRef} onSubmit={handleSubmit}> <input name="username" defaultValue="" /> <input name="password" type="password" defaultValue="" /> <button type="submit">登录</button> </form> ); }; // 3. 集成第三方库 const ThirdPartyIntegration = () => { const editorRef = useRef(null); useEffect(() => { // 初始化第三方富文本编辑器 editorRef.current = new ThirdPartyEditor('editor'); }, []); const getContent = () => { return editorRef.current.getContent(); }; return <div id="editor"></div>; };

混合使用模式

const HybridComponent = () => { const [search, setSearch] = useState(''); const fileRef = useRef(null); const handleSubmit = (e) => { e.preventDefault(); const formData = { searchTerm: search, // 来自受控输入 file: fileRef.current?.files[0] // 来自非受控输入 }; console.log('提交的数据:', formData); }; return ( <form onSubmit={handleSubmit}> {/* 受控输入:需要实时搜索建议 */} <input type="text" value={search} onChange={(e) => setSearch(e.target.value)} placeholder="搜索..." /> {/* 非受控输入:文件上传 */} <input type="file" ref={fileRef} /> <button type="submit">提交</button> </form> ); };

性能考虑

// 性能优化示例:防抖处理 const OptimizedControlledInput = () => { const [value, setValue] = useState(''); const [displayValue, setDisplayValue] = useState(''); // 防抖函数 const debouncedSetDisplayValue = useMemo( () => debounce((val) => setDisplayValue(val), 300), [] ); const handleChange = (e) => { const val = e.target.value; setValue(val); // 立即更新 state debouncedSetDisplayValue(val); // 延迟更新显示值 }; // 清理防抖函数 useEffect(() => { return () => { debouncedSetDisplayValue.cancel(); }; }, [debouncedSetDisplayValue]); return ( <div> <input value={value} onChange={handleChange} /> <p>显示的值: {displayValue}</p> </div> ); };

最佳实践建议

优先使用受控组件,当:

  • 需要实时验证和反馈

  • 表单字段之间有依赖关系

  • 需要动态禁用/启用字段

  • 要实现复杂的表单逻辑

考虑使用非受控组件,当:

  • 处理文件上传

  • 集成第三方 DOM 库

  • 表单非常简单,不需要实时验证

  • 性能是关键考虑因素,且表单项非常多

React 18 的新特性

// useDeferredValue 优化受控组件性能 const DeferredInput = () => { const [value, setValue] = useState(''); const deferredValue = useDeferredValue(value); // 使用 deferredValue 进行昂贵的计算 const expensiveResult = useMemo(() => { // 昂贵的计算 return processValue(deferredValue); }, [deferredValue]); return ( <div> <input value={value} onChange={(e) => setValue(e.target.value)} /> <div>{expensiveResult}</div> </div> ); };

总结

决策因素选择受控组件选择非受控组件
表单复杂度
实时验证需求需要不需要
性能要求一般极高
代码可维护性
测试友好度

现代 React 开发中,推荐优先使用受控组件,因为它提供更好的可预测性和可维护性。只有在有明确性能需求或特殊场景下,才考虑使用非受控组件。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 23:04:39

基于单片机的智能窗帘控制系统设计与实现

一、设计背景与核心需求 随着智能家居技术的发展&#xff0c;传统窗帘的手动操作已无法满足现代生活对便捷性、舒适性和节能性的需求。高层住宅大尺寸窗帘拉动费力、忘记关窗导致风雨侵入、光照过强影响室内环境等问题频发。基于单片机的智能窗帘控制系统&#xff0c;通过环境感…

作者头像 李华
网站建设 2026/6/9 16:59:40

Java 应用提供对接第三方接口的优雅高级写法

一、真正的高手,不是“调通接口”,而是“设计边界” 对接第三方接口,看似只是发个请求、拿个 JSON,但背后其实是——系统边界的协作与防御设计。 你面对的不是自己可控的代码,而是一个随时可能“变脸”的外部世界: 对方文档写着“此字段必传”,实际却返回 null 测试环境…

作者头像 李华
网站建设 2026/6/11 2:02:36

基于S7 - 1200 PLC的工业冷库等控制系统漫谈

基于S7-1200 PLC工业冷库控制系统 基于PLC的空调控制系统设计。 基于PLC的工业空调机组设计。基于PLC的冷风机组系统设计带解释的梯形图接线图原理图图纸&#xff0c;io分配&#xff0c;组态画面在工业领域&#xff0c;对于温度的精准控制至关重要&#xff0c;无论是冷库、空调…

作者头像 李华
网站建设 2026/6/8 1:20:01

鸿蒙Electron应用商业化效果评估:数据驱动的增长闭环

基于前文对商业化落地的探讨&#xff0c;本次将聚焦“鸿蒙Electron应用商业化效果评估体系”&#xff0c;从“核心指标构建、数据采集分析、优化迭代闭环”三个维度&#xff0c;提供可量化、可落地的评估方案&#xff0c;帮助开发者精准判断商业化健康度并高效优化。 鸿蒙Elect…

作者头像 李华
网站建设 2026/6/10 23:12:20

网络安全靶场推荐,让你通过实操能快速提升实战技能!

前言 自学网络安全知识&#xff0c;具备一定的理论基础&#xff0c;缺乏实战经验&#xff0c;想去网络靶场体验一下&#xff0c;通过实操能快速提升实战技能&#xff01; 可推荐的网络靶场&#xff1a; 1、春秋云境.com&#xff1a;平台涵盖350CVE靶标和10套大型仿真场景&am…

作者头像 李华