admin管理员组

文章数量:1026989

I'm having an Ant Design <Form> ponent with <Form.Items> which have onChange events. If the onChange event function is true I'm displaying extra content. So in the example sandbox I created, when changing all the the <Radio> to Yes it fires the onChange event which is validated and then showing a div with the text "You checked all answered with yes". As I'm using <Form> it is a form controlled environment so I'm using form to set and reset values. But when calling form.resetFields() the onChange handlers are not called. So the message won't go away as the state not refreshes. So I have to find a way to call a function from the parent ponent which refreshes the form values in the child ponent. Using useImperativeHandle() for every field to update on more plex forms to call functions from the parent seems way too plex for such a simple task. And adding custom events to municate with parent ponents seem to be a not very react way when reading this stack overflow thread Is there something from the Ant Design form I'm missing? Because this must be a mon task. What's a good way to approach this problem?

Link to code sandbox with an example:

=/src/AntDFormChild.js

Example

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 ponent to update
  };

  const handleFillForm = () => {
    form.setFieldsValue({ rjr01_q01: 1, rjr02_q01: 1 });
    // now force onChange of child ponent 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>
    </>
  );
};

I'm having an Ant Design <Form> ponent with <Form.Items> which have onChange events. If the onChange event function is true I'm displaying extra content. So in the example sandbox I created, when changing all the the <Radio> to Yes it fires the onChange event which is validated and then showing a div with the text "You checked all answered with yes". As I'm using <Form> it is a form controlled environment so I'm using form to set and reset values. But when calling form.resetFields() the onChange handlers are not called. So the message won't go away as the state not refreshes. So I have to find a way to call a function from the parent ponent which refreshes the form values in the child ponent. Using useImperativeHandle() for every field to update on more plex forms to call functions from the parent seems way too plex for such a simple task. And adding custom events to municate with parent ponents seem to be a not very react way when reading this stack overflow thread Is there something from the Ant Design form I'm missing? Because this must be a mon task. What's a good way to approach this problem?

Link to code sandbox with an example:

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

Example

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 ponent to update
  };

  const handleFillForm = () => {
    form.setFieldsValue({ rjr01_q01: 1, rjr02_q01: 1 });
    // now force onChange of child ponent 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>
    </>
  );
};
Share Improve this question edited Dec 1, 2021 at 16:22 BenjaminK asked Dec 1, 2021 at 16:17 BenjaminKBenjaminK 8331 gold badge13 silver badges33 bronze badges 0
Add a ment  | 

1 Answer 1

Reset to default 3

Since AntD Form is uncontrolled, there is no way to trigger onChange event by calling resetFields, setFieldsValues. I think your goal is to show the message depending on form values, and the best way to do is to use Form.Item, which can access form state.

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

I'm having an Ant Design <Form> ponent with <Form.Items> which have onChange events. If the onChange event function is true I'm displaying extra content. So in the example sandbox I created, when changing all the the <Radio> to Yes it fires the onChange event which is validated and then showing a div with the text "You checked all answered with yes". As I'm using <Form> it is a form controlled environment so I'm using form to set and reset values. But when calling form.resetFields() the onChange handlers are not called. So the message won't go away as the state not refreshes. So I have to find a way to call a function from the parent ponent which refreshes the form values in the child ponent. Using useImperativeHandle() for every field to update on more plex forms to call functions from the parent seems way too plex for such a simple task. And adding custom events to municate with parent ponents seem to be a not very react way when reading this stack overflow thread Is there something from the Ant Design form I'm missing? Because this must be a mon task. What's a good way to approach this problem?

Link to code sandbox with an example:

=/src/AntDFormChild.js

Example

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 ponent to update
  };

  const handleFillForm = () => {
    form.setFieldsValue({ rjr01_q01: 1, rjr02_q01: 1 });
    // now force onChange of child ponent 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>
    </>
  );
};

I'm having an Ant Design <Form> ponent with <Form.Items> which have onChange events. If the onChange event function is true I'm displaying extra content. So in the example sandbox I created, when changing all the the <Radio> to Yes it fires the onChange event which is validated and then showing a div with the text "You checked all answered with yes". As I'm using <Form> it is a form controlled environment so I'm using form to set and reset values. But when calling form.resetFields() the onChange handlers are not called. So the message won't go away as the state not refreshes. So I have to find a way to call a function from the parent ponent which refreshes the form values in the child ponent. Using useImperativeHandle() for every field to update on more plex forms to call functions from the parent seems way too plex for such a simple task. And adding custom events to municate with parent ponents seem to be a not very react way when reading this stack overflow thread Is there something from the Ant Design form I'm missing? Because this must be a mon task. What's a good way to approach this problem?

Link to code sandbox with an example:

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

Example

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 ponent to update
  };

  const handleFillForm = () => {
    form.setFieldsValue({ rjr01_q01: 1, rjr02_q01: 1 });
    // now force onChange of child ponent 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>
    </>
  );
};
Share Improve this question edited Dec 1, 2021 at 16:22 BenjaminK asked Dec 1, 2021 at 16:17 BenjaminKBenjaminK 8331 gold badge13 silver badges33 bronze badges 0
Add a ment  | 

1 Answer 1

Reset to default 3

Since AntD Form is uncontrolled, there is no way to trigger onChange event by calling resetFields, setFieldsValues. I think your goal is to show the message depending on form values, and the best way to do is to use Form.Item, which can access form state.

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

本文标签: javascriptReact Ant Design formresetFields() doesn39t call onChange event of ltFormItemsgtStack Overflow