React Ant Design form.resetFields() 不调用 <Form.Items> 的 onChange 事件

React Ant Design form.resetFields() doesn't call onChange event of <Form.Items>

我有一个带有 <Form.Items> 的 Ant Design <Form> 组件,它有 onChange 事件。如果 onChange 事件函数为真,我将显示额外的内容。 因此,在我创建的示例沙箱中,当将所有 <Radio> 更改为 Yes 时,它会触发经过验证的 onChange 事件,然后显示带有文本“You checked all answered with yes”的 div。 因为我使用 <Form> 它是一个表单控制的环境所以我使用 form 来设置和重置值。但是当调用 form.resetFields() 时,不会调用 onChange 处理程序。因此,消息不会随着状态不刷新而消失。所以我必须找到一种方法来从父组件调用一个函数来刷新子组件中的表单值。 对每个字段使用 useImperativeHandle() 来更新更复杂的表单以从父级调用函数似乎对于这样一个简单的任务来说太复杂了。阅读这篇文章时,添加自定义事件以与父组件通信似乎不是一种非常反应的方式 stack overflow thread 我缺少 Ant Design 表单中的某些内容吗?因为这一定是一个共同的任务。解决这个问题的好方法是什么?

Link 以示例代码沙箱:

https://codesandbox.io/s/vigilant-curran-dqvlc?file=/src/AntDFormChild.js

例子

const formLayout = {
  labelCol: { span: 8 },
  wrapperCol: { span: 7 }
};

const questionDefaultValues = {
  rjr01_q01: 2,
  rjr02_q01: 2
};

const AntDForm = () => {
  const [form] = Form.useForm();

  const handleResetForm = () => {
    form.resetFields();
    // now force onChange of child component to update
  };

  const handleFillForm = () => {
    form.setFieldsValue({ rjr01_q01: 1, rjr02_q01: 1 });
    // now force onChange of child component to update
  };

  return (
    <>
      <Button onClick={handleResetForm}>Reset Form</Button>
      <Button onClick={handleFillForm}>Fill Form</Button>
      <Form
        {...formLayout}
        form={form}
        initialValues={{ ...questionDefaultValues }}
      >
        <AntDFormChild form={form} />
      </Form>
    </>
  );
};

const questionQualifiedValues = {
  rjr01_q01: 1,
  rjr02_q01: 1
};

const AntDFormChild = ({ form }) => {
  const [isQualified, setIsQualified] = useState(false);
  const [questionFormValues, setQuestionFormValues] = useState({});

  useEffect(() => {
    if (shallowEqual(questionFormValues, questionQualifiedValues)) {
      setIsQualified(true);
    } else {
      setIsQualified(false);
    }
  }, [questionFormValues]);

  function shallowEqual(object1, object2) {
    const keys1 = Object.keys(object1);
    const keys2 = Object.keys(object2);
    if (keys1.length !== keys2.length) {
      return false;
    }
    for (let key of keys1) {
      if (object1[key] !== object2[key]) {
        return false;
      }
    }
    return true;
  }

  return (
    <>
      {isQualified && (
        <div style={{ color: "red" }}>You checked all answered with yes</div>
      )}
      <Form.Item name="rjr01_q01" label="Question 1">
        <Radio.Group
          onChange={(i) => {
            setQuestionFormValues((questionFormValues) => ({
              ...questionFormValues,
              rjr01_q01: i.target.value
            }));
          }}
        >
          <Radio value={1}>Yes</Radio>
          <Radio value={0}>No</Radio>
          <Radio value={2}>Unknown</Radio>
        </Radio.Group>
      </Form.Item>
      <Form.Item name="rjr02_q01" label="Question 2">
        <Radio.Group
          onChange={(i) => {
            setQuestionFormValues((questionFormValues) => ({
              ...questionFormValues,
              rjr02_q01: i.target.value
            }));
          }}
        >
          <Radio value={1}>Yes</Radio>
          <Radio value={0}>No</Radio>
          <Radio value={2}>Unknown</Radio>
        </Radio.Group>
      </Form.Item>
    </>
  );
};

由于AntD Form不受控制,所以无法通过调用resetFieldssetFieldsValues来触发onChange事件。 我认为您的目标是根据表单值显示消息,最好的方法是使用 Form.Item,它可以访问表单状态。

https://codesandbox.io/s/antd-form-item-based-on-other-item-ens59?file=/src/AntDFormChild.js