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

Created on 23 Feb 2020  ·  56Comments  ·  Source: 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

Most helpful comment

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

All 56 comments

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 将会被自动关闭。

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

Same problem here, but coludn't reproduce it on codesandbox.

+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重复警告(比错误要优雅点)。

Same problem +1

if your code involved setFieldsValue or other functions alike, call it after nodes rendered

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

or

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

It solved my problem

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

Same happens here

No fixed yet?

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

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是否存在便可;

same problem here. form is assigned but keep failing.

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

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

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

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

My workaround, create a ref by useState when Form was rendered, then check the ref before use the form instance.

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>
  );
};

No more warning again!

is it hard to discuss in English?

@muhaimincs https://ant.design/components/form/#Why-is-there-a-form-warning-when-used-in-Modal

if you use setFieldsValue, maybe try following code to replace(my foolish idea)。

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

I got it working.
Initially I was calling the antd component as
<Form blabla >

I then added the form prop in Form component -

<Form form={form} blabla >

Here the {form} comes from const [form] = Form.useForm();

Doc(That I was following) -
https://ant.design/components/form/#components-form-demo-form-in-modal

Your case might be different.

参照上面 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.

I got it working.
Initially I was calling the antd component as
<Form blabla >

I then added the form prop in Form component -

<Form form={form} blabla >

Here the {form} comes from const [form] = Form.useForm();

Doc(That I was following) -
https://ant.design/components/form/#components-form-demo-form-in-modal

Your case might be different.

This fixed it for me too. I was using the form in a drawer, not a modal

The secret combo for me was:

useEffect(() => {
if (form && visible) {
if (current) {
setTimeout (() => form.setFieldsValue({
...current,
}), 0);
} else {
form.resetFields();
}
}
}, [current]);

Same error here without modal and form prop pass to Form component
https://codesandbox.io/s/basic-usage-ant-design-demo-6llbw?file=/index.js:1618-1661

Same error here without modal and form prop pass to Form component
https://codesandbox.io/s/basic-usage-ant-design-demo-6llbw?file=/index.js:1618-1661

Fix for yours :https://codesandbox.io/s/basic-usage-ant-design-demo-ksuz8?file=/index.js

you should move the form.getVieldValue into a Form.Item component

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

another method would be to use a 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>

It happen because form element have not been rendered, but You have set values for form. I think this is basic knowledge about react and hooks.. You can use setTimeout for waiting rendered form.

But best way to set initial value of form is

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

or with this method

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

React.useEffect(()=>{
// get data values from web service or API
// fecth(...)
if (values_from_api){
setValues(values_from_api);
}
}, [])

return <>
initialValues={values}
onFinish={onFinish}
>

What if I need to use form values in my own custom hook?
With Ant 3 I did it like that:

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

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

<Form>...</Form>

With Ant 4 if I try to do it like that, I will get this error from the topic.

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

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

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

Form is in Modal, forceRender=true, destroyOnClose=false set. What am I doing wrong?

在使用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} as modal property + having the modal visible when I call form.resetFields() works for me to not show the warning

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

In this way, destroyOnClose can be also true

I use useRef instead of Form.useFrom to get Form instance, it works for me

  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>
)

Just my two cents: this error appeared for me when I tried to reset a form that was not mounted, so adding a dependency to a required constant solved it.

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

EDIT: pretty much what @fabripeco said :D

I use form in Popover, useRef is usable for me, I think it's usable for modal

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);
  }
}

My workaround, create a ref by useState when Form was rendered, then check the ref before use the form instance.

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>
  );
};

No more warning again!

solved perfectly!

Two reason case this Warning:
1. +


2."form.setFields()" or other function in useEffect()

I solve use this:

<Modal
        getContainer={false}
        // destroyOnClose
>

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

完美,再给modal添加forceRender

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

Was this page helpful?
0 / 5 - 0 ratings