函数组件中Antd的Form.create的用法(v3版本)

14,225 阅读3分钟

一 前言

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);

简单讲解:

  1. 使用create创建一个表单,接受一个组件作为参数,在组件的porps中可以得到form属性
  2. 调用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}
    />
  );
};

简单讲解:

  1. wrappedComponentRef是Form.create()自带的方法,可以接收一个ref
  2. 通过forwardRef可以进行ref转发,因为接下来我们要用到这个ref,要注意forwardRef接收参数的顺序,第一个是props,第二个是ref
  3. 通过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;

简单讲解:

  1. WrappedLoginForm中使用了mapPropsToFields和onFieldsChange,这样就建立了上层组件和表单项的关联,进而可以把整个状态保存在store中
  2. 要注意LoginForm的getFieldDecorator和WrappedLoginForm的createFormField是一一对应的关系

三 后记

Form.create可以自动帮我们处理value和onChange事件,还可以将状态维护在redux中,在表单项比较多的时候很好用,但是在只有两三个输入框的场景下,不建议使用Form.create,这样代码结构会变得有些复杂,也许我们可以直接使用input+button解决哦