受控与非受控组件
React 中受控组件和非受控组件的区别与使用场景
问题
React 中受控组件和非受控组件有什么区别?分别在什么场景下使用?
解答
受控组件
表单元素的值由 React state 控制,每次输入都会触发状态更新。
import { useState } from 'react';
function ControlledForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
// 直接使用 state 中的值
console.log({ name, email });
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="姓名"
/>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="邮箱"
/>
<button type="submit">提交</button>
</form>
);
}
非受控组件
表单元素的值由 DOM 自身管理,通过 ref 获取值。
import { useRef } from 'react';
function UncontrolledForm() {
const nameRef = useRef(null);
const emailRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
// 通过 ref 获取 DOM 元素的值
console.log({
name: nameRef.current.value,
email: emailRef.current.value,
});
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
ref={nameRef}
defaultValue=""
placeholder="姓名"
/>
<input
type="email"
ref={emailRef}
defaultValue=""
placeholder="邮箱"
/>
<button type="submit">提交</button>
</form>
);
}
对比
| 特性 | 受控组件 | 非受控组件 |
|---|---|---|
| 数据存储 | React state | DOM |
| 获取值 | 直接读取 state | 通过 ref |
| 初始值 | value + state | defaultValue |
| 实时验证 | 容易实现 | 较难实现 |
| 代码量 | 较多 | 较少 |
使用场景
受控组件适用于:
- 需要实时验证输入
- 需要根据输入动态控制 UI
- 需要格式化输入(如手机号、银行卡)
- 多个输入之间有联动关系
// 实时验证示例
function ValidatedInput() {
const [value, setValue] = useState('');
const isValid = value.length >= 3;
return (
<div>
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
{!isValid && <span style={{ color: 'red' }}>至少 3 个字符</span>}
</div>
);
}
非受控组件适用于:
- 简单表单,只需提交时获取值
- 集成第三方 DOM 库
- 文件上传(
<input type="file">只能是非受控)
// 文件上传只能用非受控
function FileUpload() {
const fileRef = useRef(null);
const handleUpload = () => {
const file = fileRef.current.files[0];
console.log(file);
};
return <input type="file" ref={fileRef} onChange={handleUpload} />;
}
关键点
- 受控组件:值存在 state,用
value+onChange - 非受控组件:值存在 DOM,用
ref+defaultValue - 需要实时响应输入变化时用受控组件
- 简单表单或文件上传用非受控组件
- React 官方推荐大多数场景使用受控组件
目录