受控组件(Controlled Components)
定义: 受控组件是指表单数据由 React 组件状态(state)管理的组件。表单元素的值由 React 通过 value 或 checked 属性控制,并通过 onChange 等事件处理程序更新状态。
代码的的表现形式:
js
import React, { Component } from "react";
import "./App.css";
export default class Form extends Component {
state = {
userName: "",
gender: "男",
hobby: [],
intro: "",
provinces: "",
};
changeUserName(e) {
this.setState({
userName: e.target.value,
});
}
changeGender(gender) {
this.setState({
gender,
});
}
changeHobby(currHobby) {
let { hobby } = this.state;
if (hobby.includes(currHobby)) {
hobby = hobby.filter((item) => item !== currHobby);
} else {
hobby.push(currHobby);
}
this.setState({
hobby,
});
}
changeProvinces(e) {
this.setState({
provinces: e.target.value,
});
}
changeIntro(e) {
this.setState({
intro: e.target.value,
});
}
submitForm(e) {
e.preventDefault();
const data = { ...this.state };
// 提交后台
}
render() {
const { userName, gender, hobby, intro, provinces } = this.state;
return (
<form>
<div className="form-item">
<label>用户名:</label>
<input value={userName} onChange={this.changeUserName.bind(this)} />
</div>
<div className="form-item">
<label>性别:</label>
<input
type="radio"
checked={gender === "男"}
name="gender"
onChange={this.changeGender.bind(this, "男")}
/>
男
<input
type="radio"
checked={gender === "女"}
name="gender"
onChange={this.changeGender.bind(this, "女")}
/>
女
</div>
<div className="form-item">
<label>爱好:</label>
<input
type="checkbox"
checked={hobby.includes("跑步")}
onChange={this.changeHobby.bind(this, "跑步")}
/>
跑步
<input
type="checkbox"
checked={hobby.includes("打篮球")}
onChange={this.changeHobby.bind(this, "打篮球")}
/>
打篮球
<input
type="checkbox"
checked={hobby.includes("旅游")}
onChange={this.changeHobby.bind(this, "旅游")}
/>
旅游
<input
type="checkbox"
checked={hobby.includes("打游戏")}
onChange={this.changeHobby.bind(this, "打游戏")}
/>
打游戏
</div>
<div className="form-item">
<label>所在省:</label>
<select value={provinces} onChange={this.changeProvinces.bind(this)}>
<option>广东省</option>
<option>江苏省</option>
<option>山东省</option>
</select>
</div>
<div className="form-item">
<label>自我介绍:</label>
<textarea
value={intro}
onChange={this.changeIntro.bind(this)}
></textarea>
</div>
<div className="form-item">
<label>自我介绍:</label>
<button onClick={this.submitForm.bind(this)}>提交</button>
</div>
</form>
);
}
}
当表单中的数据变化,对应的onChange事件就会监听到,从而更新状态(state),提交的时候就可以直接使用state上的数据。效果如下:

需要注意的是受控组件必须要有value 和onChange或者cheched和checked,少了一个可能会输入不正常,比如你将userName的上面的onchange去掉,你会发现输入框输入不了东西。
非受控组件 (Uncontrolled Components)
定义: 非受控组件是指表单数据由 DOM 自身管理的组件。你可以使用 ref 来从 DOM 中获取表单值,而不是为每个状态更新编写事件处理程序。
js
import React, { Component, createRef } from "react";
import "./App.css";
export default class Form extends Component {
constructor() {
super();
this.userNameRef = createRef();
this.maleRef = createRef();
this.femaleRef = createRef();
this.runRef = createRef();
this.basketballRef = createRef();
this.travelRef = createRef();
this.gameRef = createRef();
this.provincesRef = createRef();
this.introRef = createRef();
}
componentDidMount() {}
submitForm(e) {
e.preventDefault();
// 获取用户名
const userName = this.userNameRef.current.value;
console.log("用户名:" + userName);
// 处理性别单选框
const gender = [this.maleRef.current, this.femaleRef.current].filter(
(item) => item.checked
)[0].value;
console.log("性别:" + gender);
// 处理爱好复选框
const hobby = [
this.runRef.current,
this.basketballRef.current,
this.travelRef.current,
this.gameRef.current,
]
.filter((item) => {
return item.checked;
})
.map((item) => item.value);
console.log("爱好" + hobby);
// 获取省份
const provinces = this.provincesRef.current.value;
console.log("省份:" + provinces);
// 获取自我介绍
const intro = this.introRef.current.value;
console.log("自我介绍:" + intro);
// 提交数据
const data = {
userName,
gender,
hobby,
provinces,
intro,
};
console.log(JSON.stringify(data));
}
render() {
return (
<form>
<div className="form-item">
<label>用户名:</label>
<input ref={this.userNameRef} />
</div>
<div className="form-item">
<label>性别:</label>
<input type="radio" name="gender" ref={this.maleRef} value="男" />
男
<input type="radio" name="gender" ref={this.femaleRef} value="女" />女
</div>
<div className="form-item">
<label>爱好:</label>
<input type="checkbox" value="跑步" ref={this.runRef} />
跑步
<input type="checkbox" value="打篮球" ref={this.basketballRef} />
打篮球
<input type="checkbox" value="旅游" ref={this.travelRef} />
旅游
<input type="checkbox" value="打游戏" ref={this.gameRef} />
打游戏
</div>
<div className="form-item">
<label>所在省:</label>
<select ref={this.provincesRef}>
<option>广东省</option>
<option>江苏省</option>
<option>山东省</option>
</select>
</div>
<div className="form-item">
<label>自我介绍:</label>
<textarea ref={this.introRef}></textarea>
</div>
<div className="form-item">
<label>自我介绍:</label>
<button onClick={this.submitForm.bind(this)}>提交</button>
</div>
</form>
);
}
}
以上代码可以看出,非受控组件在处理单选框和复选框时会非常麻烦。另外还有一个注意点2个注意点:
- 想文本输入框有默认值使用defaultValue进行设置,不能使用value进行设置,否则控制会给出警告 ,例如下面代码
js
<div className="form-item">
<label>用户名:</label>
<input ref={this.userNameRef} value="hello" />
</div>
控制台:

- 想要复选框,单选框默认选中使用defaultChecked进行设置,不能使用cheched进行设置,否则控制也会给出警告,例如下面的代码:
js
<div className="form-item">
<label>爱好:</label>
<input type="checkbox" checked value="跑步" ref={this.runRef} />
跑步
<input type="checkbox" value="打篮球" ref={this.basketballRef} />
打篮球
<input type="checkbox" value="旅游" ref={this.travelRef} />
旅游
<input type="checkbox" value="打游戏" ref={this.gameRef} />
打游戏
</div>

受控组件和非受控组件的区别
特性 | 受控组件 | 非受控组件 |
---|---|---|
数据管理 | 由 React 状态管理 | 由 DOM 自身管理 |
值控制 | 通过 value /checked 属性 |
通过 ref 获取值 |
变化处理 | 需要 onChange 处理程序 |
不需要事件处理程序 |
即时验证 | 容易实现 | 较难实现 |
性能 | 每次输入都触发渲染 | 不触发额外渲染 |
表单提交 | 可直接从状态获取数据 | 需要通过 ref 或事件获取数据 |
使用场景
受控组件使用场景
需要即时验证或反馈: 例如实时显示输入是否有效
需要根据输入禁用/启用按钮: 如提交按钮在表单有效前禁用
强制特定输入格式: 如强制大写或格式化输入
多个输入相互依赖: 一个输入的值影响另一个输入
动态表单: 根据用户输入动态添加/删除表单字段
使用非受控组件的场景
简单表单,不需要即时验证: 只需在提交时获取值
文件输入: <input type="file"> 总是非受控的
与第三方库集成: 需要直接操作 DOM
性能敏感场景: 避免每次输入都触发渲染
快速原型开发: 不需要复杂逻辑的简单表单
最佳实践
-
大多数情况下推荐使用受控组件,因为它们提供了更好的控制和一致性
-
对于性能关键的表单,考虑使用非受控组件或优化受控组件(如防抖)
-
文件输入必须使用非受控组件,因为它是只读的
今天就分享到这里了感谢收看