Ant-design: Instance created by `useForm` is not connect to any Form element. Forget to pass `form` prop? 明明就是按照示例来的。

创建于 2020-02-23  ·  56评论  ·  资料来源: ant-design/ant-design

  • [ ] I have searched the issues of this repository and believe that this is not a duplicate.

Reproduction link

https://next.ant.design/components/form-cn/#components-form-demo-form-in-modal

Steps to reproduce

就直接用useForm 就行了。我参考的是弹出层中的示例。

const CollectionCreateForm = ({ onCancel }) => {
const [form] = Form.useForm();
form.setFieldsValue({
categoryName: caseDetail.categoryName,
});
return (
visible={visible}
maskClosable={false}
title="修改项目基本信息"
okText="确定"
cancelText="取消"
onCancel={onCancel}
onOk={() => {
form
.validateFields()
.then(values => {
form.resetFields();
onCreate(values);
})
.catch(info => {
window.console.log('Validate Failed:', info);
});
}}
>

form={form}
layout="vertical"
name="form_in_modal"
initialValues={{
modifier: 'public',
}}
>



name="title"
label="Title"
rules={[
{
required: true,
message: 'Please input the title of collection!',
},
]}
>







);
};

What is expected?

我只想能正常的用这个useForm

What is actually happening?

index.js:1 Warning: Instance created by useForm is not connect to any Form element. Forget to pass form prop?
in CollectionCreateForm ....

const [form] = Form.useForm();
form.setFieldsValue({
categoryName: caseDetail.categoryName,
});

form={form}
layout="vertical"
name="form_in_modal"
initialValues={{
modifier: 'public',
}}
>

| Environment | Info |
|---|---|
| antd | 4.0.0-rc.5 |
| React | 16.8.6 |
| System | mac10.15.3 |
| Browser | chrome |


我是按照官网直接来的,但是到处都报这个错,无语了。

❓FAQ

最有用的评论

I solved. In drawer, use getContainer={false} can resolved it. I think Modal is the same.
我在抽屉里用getContainer={false}就好了 Modal应该也可以 出现同样问题的可以试一下

所有56条评论

image

Hello @LamTech. Please provide a online reproduction by forking this link https://u.ant.design/codesandbox-repro or a minimal GitHub repository. Issues labeled by Need Reproduce will be closed if no activities in 7 days.

你好 @LamTech, 我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过点击 此处 创建一个 codesandbox 或者提供一个最小化的 GitHub 仓库。7 天内未跟进的 issue 将会被自动关闭。

关键在于,我这个方法用起来了,但是它一直报这个错误警告。

这里有同样的问题,但不能在 codeandbox 上重现它。

+1

在Modal上加上forceRender这个属性

可以给setFieldsValue 方法加一个延迟

调用form.resetFields(); 就有这个好像。 本地启动的 http://localhost:8001/components/form-cn/#components-form-demo-form-context 会报出。

+1
使用setFieldsValue就会出现这个警告,但是能顺利呈现,,
useForm的的实例我是传递下去的

Modal 中的 Form 默认不会渲染,可以参考 @se7en00回复 给 Modal 加上 forceRender。或者在 Modal 显示且渲染完成后再调用 setFieldsValueresetFields

在使用V4版本(form存在于函数组件中)时我也是这问题困扰了整整两天,差点崩溃了(报错但不影响使用)最后细读https://ant.design/和https://next.ant.design/发现函数组件和类中使用form一定要理解并区分函数组件中的
useEffect(() => {
return () => {
form.resetFields();
};
})
在return ()=>{....}中触发销毁的是整个函数组件(没测试此时form是否被销毁)
文档说明:destroyOnClose | 关闭时销毁 Modal 里的子元素,默认 false。forceRender | 强制渲染 Modal,默认false。
解决方法:Modal的forceRender=true,destroyOnClose=false,此时Modal销毁时(关闭),不会报错。内部代码执行时可以找到form,但会报输入控件id重复警告(比错误要优雅点)。

同样的问题+1

如果您的代码涉及setFieldsValue或其他类似函数,请在节点呈现后调用它

useEffect(() => {
  form.setFieldsValue({
    id: 1
  })
}, [])

或者

componentDidMount() {
  form.setFieldsValue({
    id: 1
  })
}

它解决了我的问题

感觉上面的都不能完全解决这个问题,能不能在form上加个属性,指示form是否有Fields,让开发人员自己 判断是否要执行后面的代码

同样发生在这里

还没修好?

上面提到的方法都试遍了,没用

Modal 中的 Form 默认不会渲染,可以参考 @se7en00回复 给 Modal 加上 forceRender。或者在 Modal 显示且渲染完成后再调用 setFieldsValueresetFields

我用的抽屉时Drawer 虽然有forcerender这个API 但是和Modal不同 抽屉的这个API不是强制渲染而是预渲染,然后还是同样报错,所以有解决办法吗?怎么判断渲染完成了?

I solved. In drawer, use getContainer={false} can resolved it. I think Modal is the same.
我在抽屉里用getContainer={false}就好了 Modal应该也可以 出现同样问题的可以试一下

可以使用useRef保存Form对象,在使用form前 先判断useRef是否存在便可;

同样的问题在这里。 表单已分配但一直失败。

如果在effect中,直接调用form.setFieldsValue, 即使加上forceRenter,重新打开Modal,还是会有这个warning,暂时解决只能effect中的setTimeout(() => form.setFieldsValue, 0)

解决了 抽屉出现的这个问题 我用getContainer={false}就不报warning了 出现同样问题的可以试一下 希望在Form的文档可以写清楚一点

谢谢,用这个方法解决了相同问题👍

你这个方法可行,能讲讲原理吗?

我的解决方法是,在呈现Form时通过useState创建一个ref ,然后在使用表单实例之前检查ref

interface FormModalProps {
  data?: RoleProps;
  visible: boolean;
  onCancel?: () => void;
  onSubmit?: (values: Store) => void;
  submitting: boolean;
}

const FormModal: React.FC<FormModalProps> = props => {
  const [form] = Form.useForm();
  const [formRef, setFormRef] = useState();  // <---- set the ref when Form Rendered

  const { data, onSubmit, onCancel, visible, submitting } = props;

  // reset Form when modal close
  useEffect(() => {
    if ( !props.visible && formRef) {  // <---- check ref before use the form instance
      form.resetFields();
    }
  }, [props.visible]);

  // fill Form when modal open
  useEffect(() => {
    if (visible && formRef) {   // <---- check ref before use the form instance
      form.setFieldsValue({
        ...data,
      });
    }
  }, [props.data]);

  // handle form onFinish
  const handleFormFinish = (values: Store) => {
    if (onSubmit) {
      onSubmit(values);
    }
  };

  // handle modal  ok
  const handleOk = () => {
    if (!form) return;
    form.submit();
  };

  return (
    <Modal
      title="Modal"
      confirmLoading={submitting}
      onOk={handleOk}
      onCancel={onCancel}
      visible={visible}
      width={640}
    >
      <Form ref={setFormRef} form={form} onFinish={handleFormFinish}>
        <Form.Item name="title" label="Title" >
          <Input />
        </Form.Item>
      </Form>
    </Modal>
  );
};

不再警告!

用英语讨论很难吗?

如果你使用 setFieldsValue,不妨试试下面的代码来替换(我的愚蠢想法)。

<Modal        **destroyOnClose**      >
        <Form **initialValues={formValues}**>
        </Form>
</Modal>

我让它工作了。
最初我将 antd 组件称为
<Form blabla >

然后我在 Form 组件中添加了 form prop -

<Form form={form} blabla >

这里的 {form} 来自const [form] = Form.useForm();

Doc(我一直在关注)-
https://ant.design/components/form/#components -form-demo-form-in-modal

您的情况可能有所不同。

https://codesandbox.io/s/form-in-modal-to-create-ant-design-demo-xvcyv
同样的问题,任何机构都可以解决这个问题???

参照上面 linxianxi , https://github.com/ant-design/ant-design/issues/21543#issuecomment-598515368

Modal 我这边可以

 <Modal
  destroyOnClose={false} 
  getContainer={false}
  forceRender
>

Modal 我这边可以

 <Modal
  destroyOnClose={false} 
  getContainer={false}
  forceRender
>

Thank you, i fixed this problem by adding forceRender props in Modal

    const [form] = Form.useForm()

    <Form form={form} >
     ....

    </Form>```


         this did the trick for me.

我让它工作了。
最初我将 antd 组件称为
<Form blabla >

然后我在 Form 组件中添加了 form prop -

<Form form={form} blabla >

这里的 {form} 来自const [form] = Form.useForm();

Doc(我一直在关注)-
https://ant.design/components/form/#components -form-demo-form-in-modal

您的情况可能有所不同。

这也为我修好了。 我在抽屉里使用表格,而不是模态

我的秘密组合是:

useEffect(() => {
如果(形式&&可见){
如果(当前){
setTimeout (() => form.setFieldsValue({
...当前的,
}), 0);
} 别的 {
form.resetFields();
}
}
}, [当前的]);

在没有模态和表单道具传递给表单组件的情况下,这里出现相同的错误
https://codesandbox.io/s/basic-usage-ant-design-demo-6llbw?file=/index.js :1618-1661

在没有模态和表单道具传递给表单组件的情况下,这里出现相同的错误
https://codesandbox.io/s/basic-usage-ant-design-demo-6llbw?file=/index.js :1618-1661

修复你的: https : =/index.js

您应该将 form.getVieldValue 移动到 Form.Item 组件中

        <Form.Item
          shouldUpdate={(prevValues, curValues) =>
            prevValues.username !== curValues.username
          }
          noStyle
        >
          {() => <div>{form.getFieldValue("username")}</div>}
        </Form.Item>

另一种方法是使用 useRef()

Draw + Form. For Modal + Form, the method applies.

  1. forceRender=true, destroyOnClose=false. It works on one of my components, but it doesn't work on the other. I find that, because of the linkage between Form.Item, my code is
const MyComp = React.memo(() => {
     const [form] = Form.useForm();
     const { getFieldValue } = form;
     const category = getFieldValue('category'); // It's the culprit
     return (/* something */);
})

Proper use: Form methods

<Form.Item
        noStyle
        shouldUpdate={(prevValues, currentValues) => prevValues.gender !== currentValues.gender}
      >
        {({ getFieldValue }) => {
          return getFieldValue('gender') === 'other' ? (
            <Form.Item name="customizeGender" label="Customize Gender" rules={[{ required: true }]}>
              <Input />
            </Form.Item>
          ) : null;
        }}
 </Form.Item>

  1. forceRender=true, destroyOnClose=false. 它对我其中一个组件起作用,但是对另一个组件不起作用。我发现,因为组件间的联动,我的代码如下
const MyComp = React.memo(() => {
     const [form] = Form.useForm();
     const { getFieldValue } = form;
     const category = getFieldValue('category'); // It's the culprit
     return (/* something */);
})

正确的使用方式: 表单方法调用

<Form.Item
        noStyle
        shouldUpdate={(prevValues, currentValues) => prevValues.gender !== currentValues.gender}
      >
        {({ getFieldValue }) => {
          return getFieldValue('gender') === 'other' ? (
            <Form.Item name="customizeGender" label="Customize Gender" rules={[{ required: true }]}>
              <Input />
            </Form.Item>
          ) : null;
        }}
 </Form.Item>

发生这种情况是因为尚未呈现表单元素,但您已为表单设置了值。 我认为这是关于 react 和 hooks 的基本知识。你可以使用 setTimeout 来等待渲染表单。

但是设置表单初始值的最佳方法是

<Form
   initialValues={{ 
      name: 'Hafid',
      age: '35'
}}
onFinish={onFinish}
>

或者用这个方法

```js
const [values, setValues] = React.useState({})

React.useEffect(()=>{
// 从 Web 服务或 API 获取数据值
// feth(...)
如果(values_from_api){
setValues(values_from_api);
}
}, [])

返回<>

初始值={值}
onFinish={onFinish}
>

如果我需要在我自己的自定义钩子中使用表单值怎么办?
使用 Ant 3 我是这样做的:

const [updating, updateInfo] = useMyOwnCustomHookForSubmitAction(getFieldsValue());

const submitForm = () => {
   validateFields((err) => {
        if (!err) updateInfo();
   });
};

<Form>...</Form>

使用 Ant 4,如果我尝试这样做,我会从主题中得到这个错误。

const [form] = useForm();
const [updating, updateInfo] = useMyOwnCustomHookForSubmitAction(getFieldsValue());

const submitForm = () => {
   validateFields((err) => {
        if (!err) updateInfo();
   });
};

<Form form={form}>...</Form>

表单在 Modal 中,forceRender=true,destroyOnClose=false 设置。 我究竟做错了什么?

在使用V4版本(form存在于函数组件中)时我也是这问题困扰了整整两天,差点崩溃了(报错但不影响使用)最后细读https://ant.design/和https://next.ant.design/发现函数组件和类中使用form一定要理解并区分函数组件中的
useEffect(() => {
return () => {
form.resetFields();
};
})
在return ()=>{....}中触发销毁的是整个函数组件(没测试此时form是否被销毁)
文档说明:destroyOnClose | 关闭时销毁 Modal 里的子元素,默认 false。forceRender | 强制渲染 Modal,默认false。
解决方法:Modal的forceRender=true,destroyOnClose=false,此时Modal销毁时(关闭),不会报错。内部代码执行时可以找到form,但会报输入控件id重复警告(比错误要优雅点)。

我也遇到这个问题,我是这样方法解决的
Modal配置forceRender | 强制渲染
Modla 表单里面 name={['modal', 'cityCode']}
筛选 表单里面 name={['search', 'cityCode']} or name='cityCode'
这样就可以 解决所有的warning 了 也不会报那个 Found 2 elements with non-unique id 警告了⚠

可以用useRef来引用form的ref, 用 formRef.current 里面的方法

const formRef = useRef()

return (<Form ref={formRef}>
  {
    (formRef.current && formRef.current.getFieldsValue('key') === 1) 
     &&
   (<Input />)
  }
</Form>)

Modal 中的 Form 默认不会渲染,可以参考 @se7en00回复 给 Modal 加上 forceRender。或者在 Modal 显示且渲染完成后再调用 setFieldsValueresetFields

在Modal上加上forceRender这个属性 根本没有用

官方的区块中的示例也警告的

在使用V4版本(form存在于函数组件中)时我也是这问题困扰了整整两天,差点崩溃了(报错但不影响使用)最后细读https://ant.design/和https://next.ant.design/发现函数组件和类中使用form一定要理解并区分函数组件中的
useEffect(() => {
return () => {
form.resetFields();
};
})
在return ()=>{....}中触发销毁的是整个函数组件(没测试此时form是否被销毁)
文档说明:destroyOnClose | 关闭时销毁 Modal 里的子元素,默认 false。forceRender | 强制渲染 Modal,默认false。
解决方法:Modal的forceRender=true,destroyOnClose=false,此时Modal销毁时(关闭),不会报错。内部代码执行时可以找到form,但会报输入控件id重复警告(比错误要优雅点)。

这个方法可以解决,但是如果在Modal外层先用三元运算符visible ? 判断下且把forceRender=true,destroyOnClose=false这样:
{visible ? : <Modal visible={visible} forceRender destroyOnClose={false}><Form form={form} onFinish={handleFinish}>...</Form></Modal> : null}
就出问题: 只显示mask 不显示弹框

这样设置forceRender=true,destroyOnClose=false,在弹框onOk或者onCancel关闭时候再使用form.resetFields()就不会再报错了
<Modal visible={visible} forceRender destroyOnClose={false} > <Form form={form} onFinish={handleFinish}>...</Form> </Modal>
但是如果在Modal外层先用三元运算符visible ? 判断下且把forceRender=true,destroyOnClose=false这样:
{visible ? <Modal visible={visible} forceRender destroyOnClose={false} > <Form form={form} onFinish={handleFinish}>...</Form> </Modal> : null }
就出问题: 只显示mask 不显示弹框

官方给出的解决方法
image
链接

在使用V4版本(form存在于函数组件中)时我也是这问题困扰了整整两天,差点崩溃了(报错但不影响使用)最后细读https://ant.design/和https://next.ant.design/发现函数组件和类中使用form一定要理解并区分函数组件中的
useEffect(() => {
return () => {
form.resetFields();
};
})
在return ()=>{....}中触发销毁的是整个函数组件(没测试此时form是否被销毁)
文档说明:destroyOnClose | 关闭时销毁 Modal 里的子元素,默认 false。forceRender | 强制渲染 Modal,默认false。
解决方法:Modal的forceRender=true,destroyOnClose=false,此时Modal销毁时(关闭),不会报错。内部代码执行时可以找到form,但会报输入控件id重复警告(比错误要优雅点)。

我也遇到这个问题,我是这样方法解决的
Modal配置forceRender | 强制渲染
Modla 表单里面 name={['modal', 'cityCode']}
筛选 表单里面 name={['search', 'cityCode']} or name='cityCode'
这样就可以 解决所有的warning 了 也不会报那个 Found 2 elements with non-unique id 警告了⚠

【表单名称,会作为表单字段 id 前缀使用】所以没有 Found 2 elements with non-unique id 警告了

getContainer={false} 作为模态属性 + 当我调用 form.resetFields() 时具有可见的模态对我来说不显示警告

useEffect(() => {
    if (form && visible) {
      form.resetFields();
    }
  }, [visible]);

这样,destroyOnClose 也可以为真

我使用 useRef 而不是 Form.useFrom 来获取 Form 实例,它对我有用

  const [visible, setVisible] = useState(false)

  let form = useRef(null)

  const closeModal = () => {
    setVisible(false)
    form.resetFields()
  }

  return (
    <Modal
      title="test"
      visible={visible}
      onCancel={closeModal}
      footer={null}
    >
      <Form
        name="test"
        layout="vertical"
        onFinish={onFinish}
        ref={instance => { form = instance }}
      >
        <Form.Item
          label="item"
          name="item"
        >
          <Input />
        </Form.Item>
        <Form.Item
          style={{
            textAlign: 'right',
          }}
        >
          <Space size="middle">
            <Button type="primary" htmlType="submit">
             submit
            </Button>
            <Button onClick={closeModal}>
             cancle
            </Button>
          </Space>
        </Form.Item>
      </Form>
    </Modal>
)

只是我的两分钱:当我尝试重置未安装的表单时出现此错误,因此向所需常量添加依赖项解决了它。

useEffect(() => {
  if (data) { // data is used to populate initialValues
    form.resetFields();
  }
}, [form, data])

编辑:几乎@fabripeco所说的:D

我在 Popover 中使用表单, useRef对我可用,我认为它可用于模态

const formRef = useRef(null);

<Popover
  content={renderEdit()}
  visible={isEdit}
  onVisibleChange={onToggleEdit}
>
  <span onClick={onToggleEdit}>
    {name}
  </span>
</Popover>

function renderEdit() {
  return (
    <Form
      initialValues={{ newName: name }}
      form={form}
      ref={formRef}
    >
    </Form>
  );
}

function onToggleEdit() {
  if (isEdit) {
    toggleEdit(false);
  } else if (!isEdit) {
    if (formRef.current) {
      form.setFieldsValue({
        newName: name
      });
    }
    toggleEdit(true);
  }
}

我的解决方法是,在呈现Form时通过useState创建一个ref ,然后在使用表单实例之前检查ref

interface FormModalProps {
  data?: RoleProps;
  visible: boolean;
  onCancel?: () => void;
  onSubmit?: (values: Store) => void;
  submitting: boolean;
}

const FormModal: React.FC<FormModalProps> = props => {
  const [form] = Form.useForm();
  const [formRef, setFormRef] = useState();  // <---- set the ref when Form Rendered

  const { data, onSubmit, onCancel, visible, submitting } = props;

  // reset Form when modal close
  useEffect(() => {
    if ( !props.visible && formRef) {  // <---- check ref before use the form instance
      form.resetFields();
    }
  }, [props.visible]);

  // fill Form when modal open
  useEffect(() => {
    if (visible && formRef) {   // <---- check ref before use the form instance
      form.setFieldsValue({
        ...data,
      });
    }
  }, [props.data]);

  // handle form onFinish
  const handleFormFinish = (values: Store) => {
    if (onSubmit) {
      onSubmit(values);
    }
  };

  // handle modal  ok
  const handleOk = () => {
    if (!form) return;
    form.submit();
  };

  return (
    <Modal
      title="Modal"
      confirmLoading={submitting}
      onOk={handleOk}
      onCancel={onCancel}
      visible={visible}
      width={640}
    >
      <Form ref={setFormRef} form={form} onFinish={handleFormFinish}>
        <Form.Item name="title" label="Title" >
          <Input />
        </Form.Item>
      </Form>
    </Modal>
  );
};

不再警告!

完美解决!

两个原因案例此警告:
1.+
2. "form.setFields()" 或 useEffect() 中的其他函数

我解决使用这个:

<Modal
        getContainer={false}
        // destroyOnClose
>

官方给出的解决方法
image
链接

完美,再给modal添加forceRender

为什么不把formHooked暴露出来让用户自己判断一下,上面那些绕来绕去的方法不觉得累吗。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

longzb picture longzb  ·  3评论

tianyacsdn picture tianyacsdn  ·  3评论

shivekkhurana picture shivekkhurana  ·  3评论

plandem picture plandem  ·  3评论

ryannealmes picture ryannealmes  ·  3评论