最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

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

matteradmin13PV0评论

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

Post a comment

comment list (0)

  1. No comments so far