一 前言
antd的Form.create用于生成表单,如果不使用其他属性,表单的数据会维护在Form内部,此时只能得到输入后的value;
如果想把表单的数据维护在上层组件或redux中,需要使用Form的createFormField,onFieldsChange以及mapPropsToFields等属性;
antd官网中基本都是class组件中使用Form.create的例子,接下来我们会通过几个简单的例子来说明如何在函数组件中使用Form.create,以及如何在上层组件得到form的实例
二 例子
例子1: 简单的登录组件
const LoginForm = (props) => {
const { form } = props;
const handleSubmit = () => {
console.log('valule', form.getFieldsValue());
};
return (
<div>
<Form layout="inline" onSubmit={handleSubmit}>
<Form.Item>
{form.getFieldDecorator('username', {
})(
<Input
placeholder="Username"
/>,
)}
</Form.Item>
<Form.Item>
{form.getFieldDecorator('password', {
})(
<Input
type="password"
placeholder="Password"
/>,
)}
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" >
Log in
</Button>
</Form.Item>
</Form>
</div>
);
};
const WrappedLoginForm = Form.create({name: 'loginForm'})(LoginForm);
简单讲解:
- 使用create创建一个表单,接受一个组件作为参数,在组件的porps中可以得到form属性
- 调用form上的方法getFieldDecorator创建表单项
例子2: 使用forward在上层组件中得到form实例
const LoginForm = forwardRef((props, ref) => {
const { form } = props;
useImperativeHandle(ref, () => ({
form,
}));
return (
<div>
<Form layout="inline" onSubmit={props.onSubmit}>
<Form.Item>
{form.getFieldDecorator('username', {
})(
<Input
placeholder="Username"
/>,
)}
</Form.Item>
<Form.Item>
{form.getFieldDecorator('password', {
})(
<Input
type="password"
placeholder="Password"
/>,
)}
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" >
Log in
</Button>
</Form.Item>
</Form>
</div>
);
});
const App = () => {
const formRef = createRef();
const handleFieldChange = () => {
console.log('formref', formRef.current?.form);
};
return (
<WrappedLoginForm
onChange={handleFieldChange}
wrappedComponentRef={formRef}
field={state}
/>
);
};
简单讲解:
- wrappedComponentRef是Form.create()自带的方法,可以接收一个ref
- 通过forwardRef可以进行ref转发,因为接下来我们要用到这个ref,要注意forwardRef接收参数的顺序,第一个是props,第二个是ref
- 通过useImperativeHandle把LoginForm的form属性传递上去,这样通过formRef就可以得到form实例,进而调用上面的方法,获得LoginForm的表单项改变后的值
例子3:将Form状态维护在上层组件或redux中
在例子2中,虽然我们可以得到子元素form的实例,但此时的结构还是维护在子元素上的,接下来我们看看如何在上层组件维护表单状态
const LoginForm = forwardRef((props, ref) => {
const { form } = props;
useImperativeHandle(ref, () => ({
form,
}));
return (
<div>
<Form layout="inline" onSubmit={props.onSubmit}>
<Form.Item>
{form.getFieldDecorator('username', {
})(
<Input
placeholder="Username"
/>,
)}
</Form.Item>
<Form.Item>
{form.getFieldDecorator('password', {
})(
<Input
type="password"
placeholder="Password"
/>,
)}
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" >
Log in
</Button>
</Form.Item>
</Form>
</div>
);
});
const App = () => {
const formRef = createRef();
const handleFieldChange = (changedFields) => {
console.log('formref', formRef.current?.form, changedFields);
};
const state = {
field: {
username: {
value: '',
},
password: {
value: '',
},
},
};
return (
<WrappedLoginForm
onChange={handleFieldChange}
wrappedComponentRef={formRef}
field={state}
/>
);
};
const WrappedLoginForm = Form.create<UserFormProps>({
name: 'loginForm',
mapPropsToFields(props) {
return {
username: Form.createFormField({
...props.field.username,
value: props.field.username?.value,
}),
password: Form.createFormField({
...props.field.passward,
value: props.field.passward?.value,
}),
};
},
onFieldsChange(props, changedFields) {
props.onChange(changedFields);
},
onValuesChange(_, values) {
console.log('value', values);
},
})(LoginForm);
export default App;
简单讲解:
- WrappedLoginForm中使用了mapPropsToFields和onFieldsChange,这样就建立了上层组件和表单项的关联,进而可以把整个状态保存在store中
- 要注意LoginForm的getFieldDecorator和WrappedLoginForm的createFormField是一一对应的关系
三 后记
Form.create可以自动帮我们处理value和onChange事件,还可以将状态维护在redux中,在表单项比较多的时候很好用,但是在只有两三个输入框的场景下,不建议使用Form.create,这样代码结构会变得有些复杂,也许我们可以直接使用input+button解决哦