简体   繁体   English

Ant 设计 React Form 在 form.resetFields() 上触发 onChange 事件

[英]Ant Design React Form fire onChange event on form.resetFields()

I'm having an Ant Design <Form> component with multiple <Form.Items> .我有一个带有多个<Form.Items>的 Ant Design <Form>组件。 One of them is a <Select> which is dependents on multiple other <Form.Item> states to change the <Options> styling depending on the combination of chosen values in the other <Form.Items> .其中之一是<Select> ,它依赖于多个其他<Form.Item>状态来更改<Options>样式,具体取决于其他<Form.Items>中所选值的组合。 I'm working with an extra useState object ( activeQuestions ) to make more complex combinations easier to handle.我正在使用额外的 useState object ( activeQuestions ) 以使更复杂的组合更易于处理。 My issue is when the form is being reset by form.resetFormFields() or set by form.setFieldsValue() it won't call my used onChange events as antd form is an uncontrolled form.我的问题是当表单由form.resetFormFields()重置或由form.setFieldsValue()设置时,它不会调用我使用的 onChange 事件,因为 antd 表单是不受控制的表单。 So I'm not sure how to approach this.所以我不确定如何解决这个问题。 There is shouldUpdate on <Form.Items> but I'm not sure how and if this is the right approach for this goal. <Form.Items>上有 shouldUpdate 但我不确定这是如何以及是否是实现此目标的正确方法。

So in the simplified example sandbox, I created, when changing all the the <Radio> to Yes it fires the onChange event which is validated, and then greying out some of the selection options.因此,在我创建的简化示例沙箱中,当将所有<Radio>更改为 Yes 时,它会触发经过验证的 onChange 事件,然后将一些选择选项变灰。

Is there something from the Ant Design form I'm missing?我缺少 Ant 设计表格中的内容吗? Because this must be a common task.因为这一定是一项共同的任务。 What's a good way to approach this problem?解决这个问题的好方法是什么?

Link to code sandbox with an example:通过示例链接到代码沙箱:

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

What I've tried (this causes an infinite loop)我尝试过的(这会导致无限循环)

 <Form.Item
        noStyle
        shouldUpdate={(prevValues, currentValues) => {
          console.log(prevValues.rjr01_q01, currentValues.rjr01_q01);
          return (
            prevValues.rjr01_q01 !== currentValues.rjr01_q01 &&
            prevValues.rjr02_q01 !== currentValues.rjr02_q01
          );
        }}
      >
        {({ getFieldValue }) => {
          setSelections((selections) => ({
            rjr01_q01: getFieldValue("rjr01_q01"),
            rjr02_q01: getFieldValue("rjr02_q01")
          }));

          return null;
        }}
      </Form.Item>

Example例子

import React, { useState, useEffect } from "react";
import { Descriptions, Form, Radio, Select, Typography } from "antd";

const { Text } = Typography;
const { Option } = Select;

const questionsData = {
  rjr01_q01: { title: "Question 1", description: "Question 1 description" },
  rjr02_q01: { title: "Question 2", description: "Question 2 description" }
};

const AntDFormChild = ({ form }) => {
  const [selections, setSelections] = useState({
    rjr01_q01: null,
    rjr02_q01: null
  });
  const [activeQuestions, setActiveQuestions] = useState([]);

  useEffect(() => {
    console.log("selections state update", selections);
    // if question 1 is yes
    if (selections.rjr01_q01 === 1 && !activeQuestions.includes("rjr01_q01")) {
      setActiveQuestions((activeQuestions) => [
        ...activeQuestions,
        "rjr01_q01"
      ]);
    }
    // if question 1 is not yes
    if (selections.rjr01_q01 !== 1 && activeQuestions.includes("rjr01_q01")) {
      setActiveQuestions((activeQuestions) => [
        ...activeQuestions.filter((i) => i !== "rjr01_q01")
      ]);
    }

    // if question 2 is yes
    if (selections.rjr02_q01 === 1 && !activeQuestions.includes("rjr02_q01")) {
      setActiveQuestions((activeQuestions) => [
        ...activeQuestions,
        "rjr02_q01"
      ]);
    }
    // if question 2 is not yes
    if (selections.rjr02_q01 !== 1 && activeQuestions.includes("rjr02_q01")) {
      setActiveQuestions((activeQuestions) => [
        ...activeQuestions.filter((i) => i !== "rjr02_q01")
      ]);
    }
  }, [selections]);

  useEffect(() => {
    console.log("activeQuestions state update", activeQuestions);
  }, [activeQuestions]);

  return (
    <>
      <Form.Item
        noStyle
        shouldUpdate={(prevValues, currentValues) => {
          console.log(prevValues.rjr01_q01, currentValues.rjr01_q01);
          return (
            prevValues.rjr01_q01 !== currentValues.rjr01_q01 &&
            prevValues.rjr02_q01 !== currentValues.rjr02_q01
          );
        }}
      >
        {({ getFieldValue }) =>
          getFieldValue("rjr01_q01") === 1 &&
          getFieldValue("rjr02_q01") === 1 ? (
            <div style={{ color: "red" }}>
              You checked all answered with yes
            </div>
          ) : null
        }
      </Form.Item>
      <Form.Item name="rjr01_q01" label="Question 1">
        <Radio.Group
          onChange={(i) => {
            setSelections((selections) => ({
              ...selections,
              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) => {
            setSelections((selections) => ({
              ...selections,
              rjr02_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="availableQuestions" label="Available Questions">
        <Select allowClear style={{ width: 250 }}>
          {Object.keys(questionsData).map((key, index) => (
            <Option key={key} value={key}>
              <Text
                style={{
                  color: activeQuestions.includes(key) && "lightgrey"
                }}
              >
                {questionsData[key].title}
              </Text>
            </Option>
          ))}
        </Select>
      </Form.Item>
    </>
  );
};

export default AntDFormChild;

You can lift your activeQuestions state to the AntDForm component and reset it together with the form:您可以将您的activeQuestions state 提升到AntDForm组件并将其与表单一起重置:

const AntDForm = () => {
  const [form] = Form.useForm();
  const [activeQuestions, setActiveQuestions] = useState([]);

  const handleResetForm = () => {
    form.resetFields();
    // now force onChange of child component to update
    // Reset active questions
    setActiveQuestions([]);
  };
 
...

Then pass it to AntDFormChild :然后将其传递给AntDFormChild

      <AntDFormChild
          form={form}
          activeQuestions={activeQuestions}
          setActiveQuestions={setActiveQuestions}
        />
      </Form>

And in <AntDFormChild> make them props instead of its own state:并在<AntDFormChild>中使它们成为道具而不是它自己的 state:

const AntDFormChild = ({ form, activeQuestions, setActiveQuestions }) => {

Here's a sandbox link showing how it works.这是一个沙盒链接,展示了它的工作原理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM