react-controlled-uncontrolled
test12026-10-2512 次阅读
表单的两种心智模型
React 里表单输入有两种写法。受控组件把值放进 state,每次按键都触发一次重渲染;非受控组件把值留在 DOM 上,只在真正需要时通过 ref 读出来。两者没有优劣,只有适用场景。
受控组件:值始终在 React 手里
受控组件的好处是数据单一来源、随时可得,适合做实时校验、根据输入动态禁用按钮。代价是每次按键都有一次渲染。
import { useState, FormEvent } from "react";
function ControlledInput() {
const [value, setValue] = useState("");
const tooShort = value.trim().length < 3;
return (
<input
value={value}
onChange={(e) => setValue(e.target.value)}
style={{ borderColor: tooShort ? "red" : "#ccc" }}
/>
);
}
非受控组件:值留在 DOM 上
非受控组件用 ref 直接读 DOM,提交时一次性取值。它适合大表单、文件上传、需要接入非 React 库,或者单纯想避免每次按键都重渲染的场景。
import { useRef, FormEvent } from "react";
function UncontrolledForm() {
const nameRef = useRef<HTMLInputElement>(null);
function onSubmit(e: FormEvent) {
e.preventDefault();
const name = nameRef.current?.value ?? "";
console.log("提交:", name);
}
return (
<form onSubmit={onSubmit}>
<input ref={nameRef} defaultValue="" />
<button type="submit">提交</button>
</form>
);
}
文件输入只能非受控
文件输入框没有 value 属性,天然是非受控的。通过 ref 读取 FileList 即可。
function AvatarUpload() {
const fileRef = useRef<HTMLInputElement>(null);
function onSubmit(e: FormEvent) {
e.preventDefault();
const file = fileRef.current?.files?.[0];
if (file) upload(file);
}
return (
<form onSubmit={onSubmit}>
<input ref={fileRef} type="file" accept="image/*" />
</form>
);
}
需要重置时,换 key 而不是清空 ref
想清空一组非受控输入,与其一个个重置,不如给外层元素换一个 key 触发整棵子树重新挂载,这才是 React 习惯的做法。
该怎么选
- 实时校验、联动禁用、输入即搜索:用受控。
- 文件上传、几十上百个字段的大表单、性能敏感:用非受控。
- React 19 起非受控也能把 ref 作为 prop 传给子组件,并可返回一个清理函数,配合 useImperativeHandle 还能暴露 reset 方法。
一句话:值要不要被 React 实时参与计算,决定了它该不该进 state。
T
test1
文章作者
表单的两种心智模型 React 里表单输入有两种写法。受控组件把值放进 state,每次按键都触发一次重渲染;非受控组...
- 分类
- 技术
- 发布时间
- 2026-10-25
- 字数
- 约 1726 字
- 阅读
- 12 次
