在 React 中,组件可以分为受控组件 (Controlled Components) 和非受控组件 (Uncontrolled Components)。这种分类主要针对处理表单元素(如 <input>, <textarea>, <select>)数据的方式。
1. 受控组件 (Controlled Components)
定义:
受控组件是指其值由 React 组件的状态 (state) 控制的表单元素。表单元素的当前值通过 value (或 checked 等) 属性从 React 的 state 中获取,并且任何用户输入都通过事件处理器(如 onChange)来更新 state,从而形成一个单向数据流。
特点:
- 数据来源单一:表单数据的唯一来源是 React 组件的
state。 - React 完全控制:React 负责渲染表单的当前值和响应用户的输入。
- 实时同步:用户输入时,
state会立即更新,UI 也随之更新。
示例:
import React, { useState } from 'react';
function NameForm() {
const [name, setName] = useState('');
const handleChange = (event) => {
setName(event.target.value); // 更新 state
};
const handleSubmit = (event) => {
event.preventDefault();
alert('提交的名字: ' + name);
};
return (
<form onSubmit={handleSubmit}>
<label>
名字:
{/* value 由 state 控制,onChange 更新 state */}
<input type="text" value={name} onChange={handleChange} />
</label>
<input type="submit" value="提交" />
</form>
);
}
在这个例子中,<input> 的 value 始终等于 name 这个 state。用户输入时,handleChange 会更新 name,然后 React 重新渲染,输入框显示新的值。React 完全“控制”了这个输入框。
2. 非受控组件 (Uncontrolled Components)
定义:
非受控组件是指其值由 DOM 自身管理的表单元素。组件的初始值可能通过 defaultValue 或 defaultChecked 设置,但之后的值变化由浏览器 DOM 自行处理,而不是通过 React 的 state。
特点:
- 数据来源是 DOM:表单数据的来源是真实的 DOM 节点。
- DOM 控制:表单元素自己维护其状态。
- 需要 Refs 访问:要读取或修改表单的值,必须使用
ref来直接操作 DOM 节点。
示例:
import React, { useRef } from 'react';
function NameForm() {
const inputRef = useRef();
const handleSubmit = (event) => {
event.preventDefault();
// 通过 ref 访问 DOM 节点的值
alert('提交的名字: ' + inputRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<label>
名字:
{/* 使用 ref 引用 DOM 节点,defaultValue 只设置初始值 */}
<input type="text" defaultValue="初始值" ref={inputRef} />
</label>
<input type="submit" value="提交" />
</form>
);
}
在这个例子中,<input> 的值由浏览器 DOM 管理。React 不跟踪输入框的当前值。只有在提交时,通过 inputRef.current.value 才能从 DOM 中读取到最新的值。
主要区别
| 特性 | 受控组件 (Controlled) | 非受控组件 (Uncontrolled) |
|---|---|---|
| 数据存储 | 存储在 React 组件的 state 中 | 存储在 DOM 节点自身中 |
| 值的控制者 | React 组件(通过 value 属性) | 浏览器 DOM |
| 数据流 | 单向数据流(state -> UI,事件 -> 更新 state) | React 只在需要时从 DOM “拉取”数据 |
| 访问值的方式 | 直接访问 state 变量 | 必须使用 ref 访问 DOM 节点 |
| 实时性 | 值与 state 实时同步 | 值可能与 React 不同步,需要手动查询 |
| 初始值属性 | value(结合 onChange) | defaultValue(仅初始值) |
| 适用场景 | 需要实时验证、动态更新、复杂表单逻辑 | 文件输入、集成非 React 库、性能敏感且不需频繁读取的场景 |
选择建议
- 优先使用受控组件:这是 React 推荐的模式。它使组件的行为更可预测、更易于调试,并且数据流清晰,便于实现表单验证、动态输入、条件渲染等复杂逻辑。
- 谨慎使用非受控组件:在某些特定场景下可能更简单,例如:
- 处理文件上传(
<input type="file" />,因为其值是只读的)。 - 集成一些不基于 React 的第三方库。
- 性能要求极高,且不需要频繁读取表单值的简单输入。
- 处理文件上传(
总结:受控组件将表单数据的“控制权”交给 React 的 state,而非受控组件则让 DOM 自己管理数据。现代 React 开发中,受控组件是标准做法,而非受控组件是一种补充手段。
THE END


