如何使用 Antd InternalFormInstance 验证表单而不显示 UI 错误

How to use Antd InternalFormInstance to validate form without display of UI Errors

我正在尝试禁用表单提交按钮,直到验证完全通过。

我遇到过关于这个话题的帖子。

此线程有助于在不显示 UI 错误的情况下触发验证: https://github.com/ant-design/ant-design/issues/25993

下面的代码在我的页脚按钮包装器的 hoc 内工作,但它正在验证要触摸的所有字段,甚至适用于非必填字段,这是不正确的和预期的。

<Form.Item shouldUpdate>
    {() => (
      <Button
        type="primary"
        htmlType="submit"
        disabled={
          !!form
            .getFieldsError()
            .filter(({ errors }) => errors.length).length
        }
      >
        Log in
      </Button>
    )}
</Form.Item>

很遗憾,https://github.com/ant-design/ant-design/issues/23281帖子全是中文,看不懂

我现有的form.validateFields指的是formInstance,但它指的是:InternalFormInstance。

如何导入并验证? antd 4版本真的支持吗?

CodeSandbox link: https://codesandbox.io/s/gallant-merkle-21izz?file=/src/withFormWrapperHOC.tsx

作为参考的示例代码会很有帮助!

当包含 select 列表时,表单验证严重失败。表单 onChange 或 onChangeValues 不起作用;当我们挖掘更多时,即使没有与 Select List.

关联的验证规则,!form.isFieldsTouched(true) 也始终为真

参考票: https://github.com/ant-design/ant-design/issues/8436

看起来 Antd 在 Rc-select api 集成方面有一些未解决的问题,但也没有公开。

我们真的应该考虑 Antd 或任何其他表单验证吗?

看起来现有的 Antd 库中存在大量用于此验证的错误,除非他们正式宣布发布,否则不支持此功能。有未解决的工单,none 已解决。

我想我暂时找不到解决这个问题的方法。

要在首次渲染时禁用验证,您可以使用 Ref 解决方法

const isMounting = React.useRef(false);
useEffect(() => {
  if (isMounting.current) {
    const disableStatus = !!form
      .getFieldsError()
      .filter(({ errors }) => errors.length).length;
    setIsDisabled(disableStatus);
  }
  else {
    isMounting.current = true
  }
}, [form]);

另一个选项是禁用登录按钮,直到填写所有表单输入,然后使用登录进行验证

import React, { useState } from "react";
import { Button, Form, Select } from "antd";
import "antd/dist/antd.css";

const { Option } = Select;

export function withFormWrapper(WrappedComponent: any) {
  return (props: any) => {
    const [form] = Form.useForm();
    const [isDisabled, setIsDisabled] = useState(true);

    function fieldIsEmpty(field) {
      let fieldValue = form.getFieldValue(field.name.join("."));
      return (
        fieldValue === undefined || [].concat(fieldValue).join().trim() === ""
      );
    }

    function fieldHasError(field) {
      return field.errors.length > 0;
    }

    function isValid() {
      const fields = form
        .getFieldsError()
        .filter((field) => fieldIsEmpty(field) || fieldHasError(field));

      console.log(fields);
      setIsDisabled(fields.length > 0);
    }

    const validate = () => {
      form
        .validateFields()
        .then((values: any) => {
          console.log("success");
        })
        .catch((errorInfo: any) => {
          console.log("failure");
        });
    };

    return (
      <Form form={form} onChange={isValid}>
        <WrappedComponent {...props} />
        <Form.Item name="gender" label="Gender" rules={[{ required: true }]}>
          <Select
            placeholder="Select a option and change input text above"
            onChange={isValid}
            allowClear
          >
            <Option value="male">male</Option>
            <Option value="female">female</Option>
            <Option value="other">other</Option>
          </Select>
        </Form.Item>
        <Form.Item>
          <Button
            type="default"
            htmlType="submit"
            onClick={() => form.resetFields()}
          >
            Cancel
          </Button>
        </Form.Item>

        <Form.Item shouldUpdate>
          {() => (
            <Button
              onClick={validate}
              type="primary"
              htmlType="submit"
              disabled={isDisabled}
            >
              Log in
            </Button>
          )}
        </Form.Item>
      </Form>
    );
  };
}

在这里工作example


使用 Form.Provider onFormChange 可以为 Select 组件触发验证

import React, { useState } from "react";
import { Button, Form, Select } from "antd";
import "antd/dist/antd.css";

const { Option } = Select;

export function withFormWrapper(WrappedComponent: any) {
  return (props: any) => {
    const [form] = Form.useForm();
    const [isDisabled, setIsDisabled] = useState(true);

    function fieldIsEmpty(field) {
      let fieldValue = form.getFieldValue(field.name.join("."));
      return (
        fieldValue === undefined || [].concat(fieldValue).join().trim() === ""
      );
    }

    function fieldHasError(field) {
      return field.errors.length > 0;
    }

    function isValid() {
      const fields = form
        .getFieldsError()
        .filter((field) => fieldIsEmpty(field) || fieldHasError(field));

      setIsDisabled(fields.length > 0);
    }

    const validate = () => {
      form
        .validateFields()
        .then((values: any) => {
          console.log("success");
        })
        .catch((errorInfo: any) => {
          console.log("failure");
        });
    };

    return (
      <Form.Provider onFormChange={isValid}>
        <Form form={form}>
          <WrappedComponent {...props} />
          <Form.Item
            name="gender"
            label="Gender"
            rules={[{ required: true }]}
            shouldUpdate
          >
            <Select
              placeholder="Select a option and change input text above"
              allowClear
            >
              <Option value="male">male</Option>
              <Option value="female">female</Option>
              <Option value="other">other</Option>
            </Select>
          </Form.Item>
          <Form.Item name="Tags" label="Tags" shouldUpdate>
            <Select
              mode="tags"
              style={{ width: "100%" }}
              placeholder="Tags Mode"
              onChange={handleChange}
            >
              {children}
            </Select>
          </Form.Item>
          <Form.Item>
            <Button
              type="default"
              htmlType="submit"
              onClick={() => form.resetFields()}
            >
              Cancel
            </Button>
          </Form.Item>

          <Form.Item shouldUpdate>
            {() => (
              <Button
                onClick={validate}
                type="primary"
                htmlType="submit"
                disabled={isDisabled}
              >
                Log in
              </Button>
            )}
          </Form.Item>
        </Form>
      </Form.Provider>
    );
  };
}

在这里工作example