先回顾一下 React 的受控组件
- 普通受控组件(例如
Switch
、Input
):
你需要自己传value
/checked
和onChange
,手动管理 state。
ini
const [checked, setChecked] = useState(false);
<Switch checked={checked} onChange={setChecked} />;
这里 Switch
的状态完全由外层 state 控制。
📦 Antd Form.Item 的做法
Form.Item
让你不必自己写 state + onChange,它会:
- 读取表单的值(Form store 里的值)。
- 把值传递给子组件 (通过
valuePropName
或getValueProps
)。 - 拦截子组件的事件 (通过
trigger
,默认是onChange
),自动更新 Form store。
✅自己封装的受控组件一样可以被 Form.Item
接管,只要满足 受控组件的契约。
🔑 什么样的组件能被 Form.Item 接管?
一个组件想要被 Form.Item
接管,至少要符合这几点:
-
有一个"值"属性
比如
value
或checked
,由外部传入。 -
有一个"触发变更"的事件
比如
onChange
,当用户交互时调用,并把新值传出去。 -
在
Form.Item
上声明:valuePropName
→ 指定用哪个属性当值(value
/checked
)。trigger
→ 指定用哪个事件更新值(默认是onChange
)。
这样 Form.Item 就能拦截你的组件,帮你和表单 store 打通。
🌰 举个例子
比如你自己封装了一个组件:
typescript
interface MySwitchProps {
value?: boolean; // 外部控制的值
onChange?: (value: boolean) => void; // 值变化时的回调
}
const MySwitch: React.FC<MySwitchProps> = ({ value = false, onChange }) => {
return (
<button
style={{
background: value ? "green" : "red",
color: "white",
padding: "4px 8px"
}}
onClick={() => onChange?.(!value)}
>
{value ? "开" : "关"}
</button>
);
};
这是一个完全受控的组件。
放到表单里,就能自动接管:
ini
<Form.Item
label="自定义开关"
name="mySwitch"
valuePropName="value" // 指定组件的受控属性
>
<MySwitch />
</Form.Item>
🧩 再复杂点:属性名不是 value
假设你写的组件属性是 checked
而不是 value
:
typescript
interface MyToggleProps {
checked?: boolean;
onChange?: (checked: boolean) => void;
}
那么 Form.Item
要这样写:
ini
<Form.Item
label="自定义 Toggle"
name="myToggle"
valuePropName="checked" // 告诉表单用 checked 作为值
>
<MyToggle />
</Form.Item>
✅ 结论:你自己封装的任何受控组件,都可以被 Form.Item
托管,只要有「值属性 + 触发事件」,并正确配置 valuePropName
/ trigger
。
ini
<Form.Item
name="myToggle"
valuePropName="checked" // 指定值的属性名
trigger="onCheckedChange" // 指定触发更新的事件名
>
<MyToggle />
</Form.Item>