说明
"非受控(Uncontrolled)"与"受控(Controlled)"是前端开发中非常核心的概念,尤其在 React 等现代前端框架中极为常见
它们主要用于描述组件(特别是表单元素)如何管理和控制自身的数据状态
受控组件(Uncontrolled Components)
在非受控组件中,表单元素的数据由 DOM 自身维护(类似于传统的原生 HTML),React 并不主动管理其内部状态
用shadcn/ui的dialog组件举例
状态由 Radix 内部自己管理(点<DialogTrigger>打开,点<DialogClose>关闭)

受控组件(Controlled Components)
在受控组件中,React 组件的 State 是数据的唯一可信源。表单元素(如 <input>)本身不存储数据,仅作为展示和交互的载体
工作机制:用户输入时触发事件(如 onChange),事件处理函数更新 React State,State 的更新再反向渲染到表单元素上,从而驱动界面的更新
新建项目的弹窗
export default function NewProjectDialog({ open, onClose }: NewProjectDialogProps) {
return (
<Dialog open={open} onOpenChange={(v) => !v && onClose()}>
<DialogContent>...</DialogContent>
</Dialog>
)
}
为什么要受控?
因为在真实软件里,"打开新建项目弹窗"可能有好几个不同的入口:
- 用户在欢迎界面点击了"新建项目"卡片
- 用户在顶部菜单栏点击了"文件 -> 新建"
这些入口都需要能够从外部直接命令弹窗打开或关闭,所以弹窗的开关状态不能封死在组件内部,必须由外部通过 open={true / false} 属性传进来控制