项目开发过程中,我们最常用到的就是Form表单,无论是Vue配合使用的ElementUI,还是React常用的Antd,都会自带表单组件。一般情况下,这些表单组件只适配了常用的表单元素(文本输入框、密码框、数字输入框、复选框、单选按钮、下拉列表、文本域等),在进行提交或校验时直接通过表单实例操作即可,那么,如何将我们自定义的组件也能够像表单元素一样与Form进行数据双向绑定呢?
众所周知,表单元素之所以能进行数据双向绑定是因为value和onChange两个属性,在React中,虽然没有数据双向绑定的概念,但我们依然可以借助这两个属性让自定义组件与Form进行交互,从而模拟数据的双向绑定。
父组件示例代码:
... ...
const [form] = Form.useForm();
const onFinish = values => {
// { username: '', password: '', count: '' }
console.info(values);
};
<Form labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} initialValues={initialValues} onFinish={onFinish} autoComplete="off">
<Form.Item label="Username" name="username" rules={[{ required: true, message: 'Please input your username!' }]}>
<Input />
</Form.Item>
<Form.Item label="Password" name="password" rules={[{ required: true, message: 'Please input your password!' }]}>
<Input.Password />
</Form.Item>
<Form.Item label="custom" name="count" rules={[{ required: true, message: 'Please check value' }]}>
<Child />
</Form.Item>
<Form.Item wrapperCol={{ offset: 8, span: 16 }}>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
... ...
自定义子组件示例代码:
function Child(props) {
const { value, onChange } = props;
const [count, setCount] = useState<number>(value);
useEffect(() => {
count !== undefined && onChange?.(count);
}, [count]);
return (
<div>
{count}
<Button
onClick={() => {
setCount(prev => Number(prev || 0) + 1);
}}
>
+1
</Button>
</div>
);
}
在上面的示例中,value和onChange是关键。Form组件内部通过context提供了表单的上下文,当表单项(即 Form.Item 的子元素)注册到Form时,它们会接收到一个特殊的 value 和 onChange(或类似的,如 onSelect、onCheck 等,取决于具体的表单元素)属性。这样在子组件中触发onChange事件时Form组件会自动处理。
这样一来,我们很多自定义开发的组件就可以与Form组件绑定,从而借助于Form的表单校验等达到很好的用户体验。