news 2026/6/16 9:36:58

受控组件 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/15 2:58:00

HTTPS 原理详解

1. HTTPS 是什么&#xff1f;HTTPS HTTP SSL/TLSHTTP&#xff1a;超文本传输协议&#xff08;明文传输&#xff09;SSL/TLS&#xff1a;安全套接层/传输层安全协议&#xff08;加密层&#xff09;2. 为什么需要 HTTPS&#xff1f;攻击类型HTTP 风险HTTPS 防护窃听数据明文传输…

作者头像 李华
网站建设 2026/6/14 21:50:22

Cookie 与 Session 的区别及 Cookie 传输机制

1. 核心区别对比表特性CookieSession存储位置客户端浏览器服务器端存储内容文本数据&#xff08;key-value&#xff09;对象数据&#xff08;通常有Session ID&#xff09;安全性较低&#xff08;可被篡改&#xff09;较高&#xff08;服务器控制&#xff09;存储大小每个域名通…

作者头像 李华
网站建设 2026/6/14 10:02:07

称重式雨雪量计:科技赋能,让降水监测更“智”在

称重式雨雪量计是一种基于称重原理的高精度、全天候降水量监测设备&#xff0c;能够准确测量液态、固态及固液混合态降水&#xff0c;广泛应用于气象、水文、农业、交通等多个领域。一、工作原理称重式雨量计基于称重原理技术&#xff0c;利用高精度称重传感器测量“降水增量”…

作者头像 李华
网站建设 2026/6/15 7:04:25

关于发那科机器人视觉补偿报警设置

! 程序名称&#xff1a;VISION_COMP! 功能&#xff1a;读取视觉系统发送的偏移量&#xff0c;并修正目标抓取位姿! 输入&#xff1a;! - GI[11]-GI[14]&#xff1a;视觉系统发送的原始补偿值&#xff08;整数&#xff09;! - PR[249]&#xff1a;预设的理论抓取目标位姿! - R[2…

作者头像 李华
网站建设 2026/6/14 9:27:37

基于单片机的多路温度检测语音报警系统设计

基于单片机的多路温度检测语音报警系统设计 第一章&#xff1a;系统设计目标与需求分析 本系统核心目标是实现多区域温度实时监测与异常语音报警&#xff0c;解决传统单路温控系统覆盖范围有限、报警方式单一的问题&#xff0c;适配工业车间、仓储库房、实验室等多场景温度管…

作者头像 李华
网站建设 2026/6/15 11:26:43

【qt】每日删除文件

QSet<QDate> cleanupDates; // 记录已执行清理的日期void saveLog(const QString &logMsg){QDateTime currentDateTime QDateTime::currentDateTime();QString dateString currentDateTime.toString("yyyy-MM-dd hh:mm:ss:zzz");// 按日期分文件存储&am…

作者头像 李华